我有一个文本文件,其中包含以下格式的多个字段。姓名:电话:地址:出生日期:工资 出生日期的格式为 mm/dd/yy。我不知道如何通过从当年减去他们的出生年份来计算特定人的年龄。我需要提取年龄,然后将其与某个年龄组进行比较,比如 50 岁。我尝试了一些东西,但它给了我奇怪的数字,比如 awk -F: '{print $4-d}' "d=$(date)" filename
2 回答
您可能想尝试:
awk -F: -v year=$(date +"%Y") '{ split($4, dob, "/"); print $1, "is", year-dob[3], "years old" }' file.txt
编辑1:
要简单地打印 60 岁以下的人的列表,请尝试:
awk -F: -v year=$(date +"%Y") '{ split($4, dob, "/"); if (year-dob[3] <= 60) print $1 }' file.txt
解释:
我假设对awk
. 该-v
选项允许awk
从 shell 中读取变量。在这种情况下,date +"Y"
只需返回当前年份。awk
具有split
允许您拆分字段的功能。在这种情况下,包含我们日期的第四个字段/
将月/日/年分开。split
将事物拆分为数组。在本例中,我将数组命名为dob
(出生日期)。第三个字段(索引 1)包含出生年份。然后在有条件的情况下进行一些快速数学运算,以检查该人的年龄是否为 60 岁以上。如果他在第一个字段中打印出他的名字。
编辑2:
再考虑一下您的问题后,很明显上述方法实际上并不能完美地计算事物。这是一项艰巨的快速工作(对不起,好吧......)。因此,这是一个更新版本,它将更加准确。像这样运行:
awk -f script.awk file.txt
内容script.awk
:
BEGIN {
FS=":"
"date +\"%s\"" | getline cdate
}
{
rdate = gensub(/([0-9]+)\/([0-9]+)\/([0-9]+)/, "\\3-\\1-\\2", "g", $4)
cmd = "date -d " rdate " +\"%s\""
while (( cmd | getline result ) > 0 ) {
if ((cdate - result) / 31556926 <= 60) {
print $1
}
}
}
编辑3:
或者没有外部命令和 getline:
BEGIN {
FS=":"
cdate = systime()
}
{
rdate = gensub(/([0-9]+)\/([0-9]+)\/([0-9]+)/, "\\3 \\1 \\2 0 0 0", "g", $4)
result = mktime(rdate)
if ((cdate - result) / 31556926 <= 60) {
print $1
}
}
使用 GNU awk(应该可以工作但未经测试,因为您没有提供任何示例输入和预期输出):
BEGIN{
FS = ":"
nowSecs = systime()
nowYear = strftime("%Y",nowSecs)
nowDay = strftime("%j",nowSecs)
}
{
# input date format is MM/DD/YY
dobSpec = gensub(/([0-9]+)\/([0-9]+)\/([0-9]+)/, "\\3 \\1 \\2 0 0 0", "", $4)
dobSecs = mktime("20" dobSpec)
if ( (dobSecs > nowSecs) || (dobSecs < 0) ) {
# guessed the wrong century so try again
dobSecs = mktime("19" dobSpec)
}
dobYear = strftime("%Y",dobSecs)
dobDay = strftime("%j",dobSecs)
diffYears = nowYear - dobYear
diffDays = nowDay - dobDay
age = diffYears + (diffDays >= 0 ? 1 : 0)
if ( age < 60 ) {
print
}
}
作为替代方案,这是@steve 的解决方案在不使用外部调用 shell 日期和后续 getline 的情况下的样子:
BEGIN {
FS=":"
cdate = systime()
}
{
rdate = gensub(/([0-9]+)\/([0-9]+)\/([0-9]+)/, "\\3 \\1 \\2 0 0 0", "g", $4)
result = mktime(rdate)
if ((cdate - result) / 31556926 <= 60) {
print $1
}
}
I didn't go that route as I didn't want to use the seconds-per-year approximation since I think there are edge cases where that wouldn't work. Like @steve's original, the second solution above will need to be modified to provide the missing century in the input year just like I did in my first solution above.