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 {} +