创建包含文件名的新文件并计算每个文件
Create new file containing filename and count each file
我需要创建一个包含文件名和行数的新 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
解决方案使用 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
为了 运行 shell 在 find
的结果上添加一些不破坏任何特殊字符的方式,您可以使用 find -exec sh -c ...
。 (见下文)。
在这种情况下,如果您可以使用 bash 的 extglob
为您匹配子目录,则您并不需要它。我刚刚意识到这是一个 ksh
问题,如果它有等同的东西,我就知道了。
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
看它是否是一个目录,即使是在 d_type
字段中填写 readdir(3) 结果。)
请注意,对于 extglob,您 需要 dir/**/*.gz
,而不仅仅是 dir/**.gz
更一般地说,您可以通过使用 xargs 运行 sh -c
,然后在 [=25] 中将 find
与 xargs
和 shell 命令一起使用=], 遍历位置参数。 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
本身,如果你有 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] (传统上是命令名称)。
我需要创建一个包含文件名和行数的新 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
解决方案使用 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
为了 运行 shell 在 find
的结果上添加一些不破坏任何特殊字符的方式,您可以使用 find -exec sh -c ...
。 (见下文)。
在这种情况下,如果您可以使用 bash 的 extglob
为您匹配子目录,则您并不需要它。我刚刚意识到这是一个 ksh
问题,如果它有等同的东西,我就知道了。
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
看它是否是一个目录,即使是在 d_type
字段中填写 readdir(3) 结果。)
请注意,对于 extglob,您 需要 dir/**/*.gz
,而不仅仅是 dir/**.gz
更一般地说,您可以通过使用 xargs 运行 sh -c
,然后在 [=25] 中将 find
与 xargs
和 shell 命令一起使用=], 遍历位置参数。 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
本身,如果你有 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] (传统上是命令名称)。