我正在使用 awk 向 CSV 文件添加一列。文件的每一行都以日期和时间开头。我希望新列是那个时间作为 Unix 纪元时间戳。
我将前三个字段提供给“日期”,这确实给了我时间戳,但有一些我不想要的杂散逗号“,”。下面是一个简化版本,只打印一个时间戳列作为输出。输入文件:
08/17/2020 21:46:04 -700 , 1 , 2 , 3
08/17/2020 21:47:03 -700 , 1 , 2 , 3
08/17/2020 21:48:03 -700 , 1 , 2
08/17/2020 21:49:04 -700 , 1 , 2
Run Code Online (Sandbox Code Playgroud)
这是我的程序:
cat input.csv | awk '{
tmp=$(system("date +%s -d \""$1" "$2" "$3"\""));
printf("%s", $tmp );
}'
Run Code Online (Sandbox Code Playgroud)
这是输出。这就是我所期望的,除了第 2 行和第 3 行的前导逗号。我认为 'tmp' 变量从 'date' 获得结果,包括一个尾随换行符,但有时在换行符后还有一个逗号。这似乎取决于输入文件中有多少字段跟随前三个,但我只引用前三个,如 $1 $2 $3 所以输入行的其余部分不起作用(?)为什么那些逗号出现在输出,我怎么能删除它们?有一个更好的方法吗?
1597725964
,1597726023
,1597726083
1597726144
Run Code Online (Sandbox Code Playgroud)
尝试:
$ while read -r line; do date +%s -d "${line%%,*}"; done < input.csv
1597725964
1597726023
1597726083
1597726144
Run Code Online (Sandbox Code Playgroud)
while read -r line; do开始一个while循环并从标准输入读取一行。
"${line%%,*}" 从行中删除逗号及其后的所有内容。
date +%s -d "${line%%,*}" 将日期打印为纪元。
done完成while循环。
<input.csv 为循环提供标准输入。
这将打印整行并将纪元添加为最后一列:
$ while read line; do printf "%s, %s\n" "$line" $(date +%s -d "${line%%,*}"); done < input.csv
08/17/2020 21:46:04 -700 , 1 , 2 , 3, 1597725964
08/17/2020 21:47:03 -700 , 1 , 2 , 3, 1597726023
08/17/2020 21:48:03 -700 , 1 , 2, 1597726083
08/17/2020 21:49:04 -700 , 1 , 2, 1597726144
Run Code Online (Sandbox Code Playgroud)
在awk你可以使用 getline 而不是 system() 的协进程:
< input.csv awk -F' , ' '{
"date +%s -d \047"$1"\047\n" | getline date
print date
}'
1597725964
1597726023
1597726083
1597726144
Run Code Online (Sandbox Code Playgroud)
的帮助下Inian和奥古兹·伊斯梅尔的意见,并且gawk,我们想出了一个更好的解决方案,其中写入最新的标准输入,而不是通过命令行传递参数给它。这更好,因为将变量插入命令行总是伴随着 shell 命令注入的风险(通过 input.csv)。
< input.csv gawk -F' , ' '{
cmd = "date +%s -f-";
print $1 |& cmd;
close(cmd, "to");
if ((cmd |& getline line) > 0)
print line; close(cmd)
}'
1597725964
1597726023
1597726083
1597726144
Run Code Online (Sandbox Code Playgroud)
感谢两位!
调用system(...)返回零,因此tmp被赋值$(0),即整个输入行。观察:
$ echo a b c d | awk '{ x = $(system("exit 3")); print x }'
c
Run Code Online (Sandbox Code Playgroud)
无法使用systemawk 中的函数捕获 shell 命令的输出;hek2mgl 的回答演示了如何正确地做到这一点。
然后在printf(...)调用$tmp中扩展为$8,因为$0构成有效数字的最长前缀是08; 因此输出中的逗号。可以这样证明:
$ echo foo bar | awk '{ x = "0002junk"; print $x }'
bar
Run Code Online (Sandbox Code Playgroud)
无论如何,为了完成问题中描述的任务,您实际上并不需要 awk。cut和 GNU的结合date产生所需的输出。
$ cut -d, -f1 input.csv | date -f- +%s
1597725964
1597726023
1597726083
1597726144
Run Code Online (Sandbox Code Playgroud)
并且使用paste,如果您不介意逗号周围缺少空格,您可以将这些时间戳附加到相应的记录。
$ cut -d, -f1 input.csv | date -f- +%s | paste -d, input.csv -
08/17/2020 21:46:04 -700 , 1 , 2 , 3,1597725964
08/17/2020 21:47:03 -700 , 1 , 2 , 3,1597726023
08/17/2020 21:48:03 -700 , 1 , 2,1597726083
08/17/2020 21:49:04 -700 , 1 , 2,1597726144
Run Code Online (Sandbox Code Playgroud)
您能否尝试在 GNU 中遵循、编写和测试awk。您可以在使用它的同时使用它自己的mktime功能,awk您不需要使用外部命令awk本身可以照顾它。
awk '
{
split($2,array,":")
print mktime(substr($0,7,4)" "substr($0,1,2)" "substr($0,4,2) OFS array[1] OFS array[2] OFS array[3])
}' Input_file
Run Code Online (Sandbox Code Playgroud)