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

Shell 创建包含文件名的新文件并计算每个文件的数量,shell,unix,sh,ksh,Shell,Unix,Sh,Ksh,我需要创建一个新的文件\u 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.t

我需要创建一个新的
文件\u 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
使用for循环的解决方案

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
您也可以尝试:

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

要在
find
的结果上运行shell stuff,并且不破坏任何特殊字符,可以使用
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也不如find智能。它总是
stat
s查看它是否是目录的一切,即使在结果中填充
d_type
字段的文件系统上也是如此。)

注意,对于extglob,您确实需要
dir/***.gz
,而不仅仅是
dir/***.gz


更一般地说,您可以将
find
xargs
和shell命令一起使用,方法是让xargs运行
sh-c
,然后在该
-c
内循环位置参数<代码>对于i是隐式的;i、 e.它相当于“$@”中i的

如果您有一个支持
+
终止符的
-exec
find
(将匹配列表放在一个命令行上),您可以将其简化为让
find
运行
sh-c
本身:


在这两种情况下,您都需要在
find
xargs
中的args之前添加一个伪arg
,因为这将最终成为argv[0](传统上是命令名).

我想你想要
.txt
文件解压后的行数?你有
zcat
吗?还是我们需要使用
gunzip-c
?我想zcat会有用的。我通常对每个文件都使用zcat filename | wc-l。如果你不介意表格的话,我添加了另一个提供预期输出的解决方案。如果解决方案令您满意,您应该将问题标记为已回答。您确定-c选项吗?至少在我的ubuntu中,“=l”是可以使用的选项。“-c”在屏幕上显示了大量数据我认为输出符合我的要求:)查找-print0 | xargs-0
有何帮助?您也可以使用默认的
find-print
。(当然,您应该使用
-exec sh-c…
)。作为对…中文件的
求值的一部分,您仍在对命令替换的结果进行分词和全局扩展。您甚至不需要在gunzip的命令行中引用
“$file”
。因此,您有一些好主意,但这将与带空格的文件名分开。不要忘记
IFS=
,以避免从文件名中去掉前导/尾随空格。或者看看我的答案,有几种方法可以在包含换行符的文件名上实现收支平衡。很好。在我自己的脚本中,我很少担心不会从文件名中去掉前导/尾随空格,因为我的文件系统上的所有文件名都是正常的。但对于更广泛的世界来说,这是不可能被假定的……这里也是如此。我的一行程序通常是“相当”安全的,即使我不需要它们。几个月前,我对改进bash完成中的代码很感兴趣,严格的shell安全性很难实现。特别是对于补全,补全生成器是一个命令,它接受模式参数并生成要读入数组的输出…是的,我总是寻找新的工具添加到我的bash工具箱中,并尝试将注意力集中在所有的
I
t
,但在本地使用100次之后,只需完成任务,
i
t
似乎从旧灰质的最前沿消失了。谢谢你的提醒。。。再说一次……可怜的sap通常是一个Linux系统管理员,他通过samba共享支持windows工作人员,最终得到一堆只有拼字板才会喜欢的毫无意义的文件名。当我在1999年为我的办公室构建第一个Linux后端时,我在所有的工作站上都放了一个文件名格式表,只是为了防止这种胡说八道。有些人是如何开始在“文件保存”对话框中输入小说的,我不知道,但是,唉,自从双软盘时代以来,许多人也没有出现过。。。
find -name '*.gz` -print0 | xargs -0 bash -c 'for i in "$@";do ...loop body from above...;done > linecounts.txt' bash
find -name '*.gz` -exec bash -c 'for i in "$@";do ...loop body from above...;done > linecounts.txt' bash {} +