我有命令:
awk 'BEGIN{print "Name, Number"}/value/{print FILENAME, "," $8}' *.txt >> out.csv
它可以完美地浏览目录中的 txt 文件、解析值并写入带有标题(名称、编号)的最终 csv 文件。
我的问题是我有“太多”,所以我用 find 和 xarg 修改它:
find ./ -maxdepth 1 -type f -name '*.txt' | xargs awk 'BEGIN{print "Name, Number"}/value/{print FILENAME, "," $8}' | sed 's/\.\///g' >> out.csv
这在过去是有效的,但现在我发现,有时,标题会多次写入最终的 csv 文件。我不知道为什么。它确实与目录中 txt 文件的总数相关,这样如果我达到某个数字,就会发生这种情况,但我不太确定。
谢谢。
答案1
将按find
批次文件调用 awk,因此将BEGIN
每批次执行一次,而不是按照您的需要对所有文件执行一次。您可以让 awk 读取所有文件作为输入并填充其内部文件数组以从中读取 ( ARGV[]
) ,而不是使用所有文件作为参数调用 awk 并使 shell 因“参数过多”错误而失败:
find ./ -maxdepth 1 -type f -name '*.txt' |
awk '
BEGIN { OFS=","; print "Name", "Number" }
NR==FNR { ARGV[ARGC++]=$0; next }
/value/ { print substr(FILENAME,3), $8 }
' - > out.csv
我还在 awk 脚本中整理了一些内容,并删除了 sed 的管道,因为当您使用 awk 时,您永远不需要 sed。我更改>>
为,>
因为我假设您希望在调用上述命令时从头开始创建输出文件而不是附加到它。
上面假设您的文件名都不包含换行符。如果确实如此,则使用 GNU 工具并将其添加-print0
到命令末尾find
和RS="\0";
awk 命令的 BEGIN 部分。它还假设您的文件名不包含"
,那么输出将不是有效的 CSV,但是您所说的第一个脚本可以完美地工作,除了“参数太多”问题之外,如果您的文件名包含其中任何一个,那么它们将失败一定不。
答案2
在组命令(即包含在and中)或子 shell 中(即包含在and 中)运行find
and并在运行之前打印标头。将整个组命令或子 shell 的输出重定向到输出文件。awk
{
}
(
)
find
例如:
{
echo "Name,Number"
find ./ -maxdepth 1 -type f -name '*.txt' -exec \
awk -v OFS=, '
FNR==1 { fn = FILENAME; sub(/^\.\//, "", fn };
/value/ {print fn, $8}' {} +
} >> out.csv
笔记:
- 查看
man bash
并搜索Compound Commands
- 你不需要
xargs
在这里 - 使用 find 的-exec
选项,例如find ... -exec awk ... {} +
。 - 您也不需要
sed
- awk 的内置sub()
函数可用于删除./
来自find
. BTW,gsub()
可用于全局搜索和替换,/g
就像sed
.