创建包含文件名的新文件并计算每个文件

时间:2015-11-21 08:07:21

标签: shell unix sh ksh

我需要创建一个包含文件名和行数的新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

3 个答案:

答案 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

更一般地说,您可以将findxargs和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 {} +

在这两种情况下,findxargs的args之前需要一个虚拟arg ,因为这将最终成为argv [0](传统上是命令名称) )。