我有一个巨大的文件需要分成多个文件。
我正在使用split
,效果很好
file=home/sap/dim/deltafile.D2017313.T100058932IDL.gz
gunzip -c ${file} | split -l 10000000 -d -a 4 - ${file%/*}/"working".$v_procid.`basename ${file%.*}`.part.
有了awk
它也能工作。但是当我传递变量时awk
,它失败了。
gunzip -c ${file} | awk 'NR%10000000==1 {x="F" ++i} {print > x}'
awk
创建名为F1
, F2
...的文件
我需要使用变量,并且尝试了所有不同的示例。没有运气。
答案1
您可以将数据传递给awk
with -v var=value
,可以存在任意数量的 -v 选项:
awk -v foo=FOO 'END {print foo}' </dev/null
awk -v foo=FOO -v bar=BAR 'END {print foo, bar}' </dev/null
像往常一样,您还可以使用 shell 变量等作为赋值的一部分:
awk -v bar="$PWD" 'END {print bar}' </dev/null
file=home/sap/dim/deltafile.D2017313.T100058932IDL.gz
awk -v bar="${file%/*}" 'END {print bar}' </dev/null
答案2
在外部构造文件名的静态部分awk
并将其传递给awk
变量:
prefix="${file%/*}/working.$v_procid.$(basename ${file%.*}).part"
gunzip -c "$file" |
awk -v p="$prefix" 'NR % 10000000 == 1 { f = p "" ++i } { print >f }'
该f = p "" ++i
位可以替换为f = sprintf("%s%s", p, ++i)
。
如果您希望生成大量输出文件,则可能需要close()
在写入下一个输出文件之前显式显示前一个文件,这样您就不会意外用完可用的文件描述符:
awk -v p="$prefix" 'NR % 10000000 == 1 { if (f) close(f); f = p "" ++i } { print >f }'
答案3
对前两个答案还有一点要补充。还有第二种传递变量的方法,即在指定程序后将它们添加到命令行。
awk program.awk /path/to/input var=value second/input
文件名参数和变量赋值参数之间的区别是在 awk 即将打开下一个输入文件时进行的。在执行过程中,它会检查文件名以查看它是否确实是变量赋值;如果是这样,awk 设置变量而不是读取文件。
因此,在读取所有先前指定的文件后,变量实际上会收到给定值。特别是,以这种方式分配的变量值在 BEGIN 规则内不可用(请参阅 BEGIN/END),因为此类规则在 awk 开始扫描参数列表之前运行。
所以虽然
awk -v var=value program.awk
允许您在任何 BEGIN 部分之前传递程序开始的值,如果需要,您还可以随时更改程序变量。