我需要创建一个包含文件名和行数的新file_count.txt
。
目录结构
$ find asia emea -name \*.gz
asia/2013/emp_asia_13.txt.gz
asia/2015/emp_asia_15.txt.gz
asia/2014/emp_asia_14.txt.gz
emea/2013/emp_emea_13.txt.gz
emea/2015/emp_emea_15.txt.gz
emea/2014/emp_emea_14.txt.gz
输出文件应该是:
emp_asia_13.txt.gz 20
emp_asia_15.txt.gz 15
emp_asia_14.txt.gz 50
emp_emea_13.txt.gz 32
emp_emea_15.txt.gz 26
emp_emea_14.txt.gz 70
答案 0 :(得分:3)
使用进行循环的解决方案
for file in $(find asia emea -name \*.gz -print0 | xargs -0)
do
echo -n $(basename $file);
gunzip -c $file |wc -l;
done >> file_count.txt
在一行中,它给出了:
$ for file in $(find asia emea -name \*.gz -print0 | xargs -0); do echo -n $(basename $file); gunzip -c $file |wc -l; done >> file_count.txt
输出是:
$ cat file_count.txt
emp_asia_13.txt.gz 4
emp_asia_14.txt.gz 10
emp_emea_15.txt.gz 17
答案 1 :(得分:3)
您也可以尝试:
find asia emea -type f -name "*gz" | while IFS= read -r fname; do
printf "%s %s\n" "$fname" $(gzip -dc "$fname" | wc -l) >> file_count.txt
done
作为1-liner将是:
find asia emea -type f -name "*gz" | while IFS= read -r fname; do printf "%s %s\n" "$fname" $(gzip -dc "$fname" | wc -l) >> file_count.txt; done
答案 2 :(得分:1)
要以不会破坏任何特殊字符的方式对find
的结果运行shell内容,您可以使用find -exec sh -c ...
。 (见下文)。
在这种情况下,如果您可以使用bash的extglob
来匹配子目录,那么您真的不需要这样做。我刚刚意识到这是一个ksh
问题,而IDK是否有相同的东西。
shopt -s extglob
for i in {asia,emea}/**/*.gz;do
bn=${i##*/} # basename
printf "%s %s\n" "$bn" "$(zcat "$i"|wc -l)" # stolen from David's answer
done > linecounts.txt # redirect once outside the loop.
这就像David的答案,除非它甚至在名称中包含换行符的文件中成功计算行数。但是,输出文件会很麻烦,因为换行是文本数据的常用记录分隔符,所以将它放在文件名中只是在寻找麻烦。
如果你知道你的目录结构,你不需要extglob,只能使用*/*/*.gz
。可选地使用一些前导字符来切断一些子目录搜索。 (bash并不像遍历目录时那样聪明。它总是stat
所有内容都可以查看它是否是一个目录,即使在填充d_type
字段的文件系统上也是如此。 readdir(3)结果。)
请注意,使用\ textglob, 需要dir/**/*.gz
,而不仅仅是dir/**.gz
更一般地说,您可以将find
与xargs
和shell命令一起使用,让xargs运行sh -c
,然后在-c
内部循环使用位置参数。 for i
隐含地做到了;即它相当于for i in "$@"
。
find -name '*.gz` -print0 | xargs -0 bash -c 'for i in "$@";do ...loop body from above...;done > linecounts.txt' bash
如果find
支持sh -c
的{{1}}终止符,则可以将此简化为让find
运行+
本身(放置一个-exec
一个命令行上的匹配列表):
find -name '*.gz` -exec bash -c 'for i in "$@";do ...loop body from above...;done > linecounts.txt' bash {} +
在这两种情况下,在find
或xargs
的args之前需要一个虚拟arg ,因为这将最终成为argv [0](传统上是命令名称) )。