我使用命令wc -l
计算文本文件中的行数(我也希望通过管道对所有内容进行排序),如下所示:
wc -l $directory-path/*.txt | sort -rn
输出包括"总计" line,这是所有文件的行总和:
10 total
5 ./directory/1.txt
3 ./directory/2.txt
2 ./directory/3.txt
有没有办法压制此摘要行?或者甚至更好,改变总结线的措辞方式?例如,代替" 10",而不是""" line"而不是"总计"单词" file"。
答案 0 :(得分:3)
sed
解决方案!由于总计在最后一行上传,$d
是用于删除最后一行的sed命令。
wc -l $directory-path/*.txt | sed '$d'
wc -l $directory-path/*.txt | sed '$d;1ilines total'
不幸的是,没有对齐。
wc -l $directory-path/*.txt |
sed -e '
s/^ *\([0-9]\+\)/ \1/;
s/^ *\([0-9 ]\{11\}\) /\1 /;
/^ *[0-9]\+ total$/d;
1i\ lines filename'
将完成这项工作
lines file
5 ./directory/1.txt
3 ./directory/2.txt
2 ./directory/3.txt
wc
版本确实可以将总数放在第一行:这个是有趣的,因为我不相信有一个wc
版本将总数放在第一行,但是......
此版本随处删除总行,并在输出顶部添加标题行。
wc -l $directory-path/*.txt |
sed -e '
s/^ *\([0-9]\+\)/ \1/;
s/^ *\([0-9 ]\{11\}\) /\1 /;
1{
/^ *[0-9]\+ total$/ba;
bb;
:a;
s/^.*$/ lines file/
};
bc;
:b;
1i\ lines file' -e '
:c;
/^ *[0-9]\+ total$/d
'
这更复杂,因为我们不会放弃第一行,即使它是总行。
答案 1 :(得分:1)
这实际上相当棘手。
我的基础是wc
命令的GNU coreutils版本。请注意,total
行通常是最后打印的,而不是第一行(请参阅我对该问题的评论)。
wc -l
为每个输入文件打印一行,包括文件中的行数,后跟文件名。 (如果没有文件名参数,则省略文件名;在这种情况下,它会计算stdin中的行。)
当且仅当有多个文件名参数时,它会打印一个包含总行数和单词total
的最后一行。文档表明无法禁止该汇总行。
除了事先在其他输出之前,该行与名称恰好为total
的文件的输出无法区分。
因此,为了可靠地过滤掉total
行,您必须读取wc -l
的所有输出,并仅在输出的总长度大于1时删除最后一行。 (如果你的名字中有换行符的文件可能会失败,但你可能会忽略这种可能性。)
更可靠的方法是单独调用每个文件wc -l
,避免使用total
行:
for file in $directory-path/*.txt ; do wc -l "$file" ; done
如果你想对输出进行排序(你在评论中提到但在你的问题中没有提到):
for file in $directory-path/*.txt ; do wc -l "$file" ; done | sort -rn
如果您碰巧知道没有名为total
的文件,那么快速而肮脏的方法是:
wc -l $directory-path/*.txt | grep -v ' total$'
如果你想对所有文件运行wc -l
,然后过滤掉total
行,这里有一个应该完成这项工作的bash脚本。根据需要调整*.txt
。
#!/bin/bash
wc -l *.txt > .wc.out
lines=$(wc -l < .wc.out)
if [[ lines -eq 1 ]] ; then
cat .wc.out
else
(( lines-- ))
head -n $lines .wc.out
fi
rm .wc.out
另一个选择是这个Perl单行:
wc -l *.txt | perl -e '@lines = <>; pop @lines if scalar @lines > 1; print @lines'
@lines = <>
将所有输入转换为字符串数组。 pop @lines
会丢弃最后一行,如果有多个,即最后一行是total
行。
答案 2 :(得分:1)
程序wc,当它们是两个或两个以上的文件(wc.c的片段)时,总是显示总数:
if (argc > 2)
report ("total", total_ccount, total_wcount, total_lcount);
return 0;
最简单的方法是使用只有一个文件的wc并找到一个接一个的文件到wc:
find $dir -name '*.txt' -exec wc -l {} \;
或者由liborm指定。
dir="."
find $dir -name '*.txt' -exec wc -l {} \; | sort -rn | sed 's/\.txt$//'
答案 3 :(得分:0)
你能用另一个wc吗?
POSIX wc
(man -s1p wc
)显示
如果指定了多个输入文件操作数,则应写入与其他行格式相同的附加行,除了应写入total(在POSIX语言环境中)而不是路径名和总数每栏的内容应酌情书写。这样的附加行(如果有的话)写在输出的末尾。
你说Total line是第一行,手册说明了最后一行,其他wc根本没有显示。删除第一行或最后一行是危险的,所以我grep -v
行总数(在POSIX语言环境中......),或者只是grep所有其他行的斜杠:
wc -l $directory-path/*.txt | grep "/"
答案 4 :(得分:0)
不是最优化的方式,因为您可以使用cat
,echo
,coreutils
,awk
,sed
,tac
的组合,等,但这会让你想要你想要的:
wc -l ./*.txt | awk 'BEGIN{print "Line\tFile"}1' | sed '$d'
wc -l ./*.txt
将提取行数。 awk 'BEGIN{print "Line\tFile"}1'
将添加标题标题。 1
对应于标准输入的第一行。 sed '$d'
将打印除最后一行之外的所有行。
示例结果
Line File
6 ./test1.txt
1 ./test2.txt
答案 5 :(得分:0)
grep -c
由于这些问题,我很少在脚本中使用wc -l
。我改用grep -c
。虽然它不如wc -l
那么高效,但我们不需要担心其他问题,例如汇总行,空格或分支额外流程。
例如:
/var/log# grep -c '^' *
alternatives.log:0
alternatives.log.1:3
apache2:0
apport.log:160
apport.log.1:196
apt:0
auth.log:8741
auth.log.1:21534
boot.log:94
btmp:0
btmp.1:0
<snip>
单个文件非常简单:
line_count=$(grep -c '^' my_file.txt)
grep -c
vs wc -l
/tmp# ls -l *txt
-rw-r--r-- 1 root root 721009809 Dec 29 22:09 x.txt
-rw-r----- 1 root root 809338646 Dec 29 22:10 xyz.txt
/tmp# time grep -c '^' *txt
x.txt:7558434
xyz.txt:8484396
real 0m12.742s
user 0m1.960s
sys 0m3.480s
/tmp/# time wc -l *txt
7558434 x.txt
8484396 xyz.txt
16042830 total
real 0m9.790s
user 0m0.776s
sys 0m2.576s
答案 6 :(得分:0)
您可以使用 GNU Parallel 这样简洁地解决它(以及其他许多需要for
循环的问题):
parallel wc -l ::: tmp/*txt
示例输出
3 tmp/lines.txt
5 tmp/unfiltered.txt
42 tmp/file.txt
6 tmp/used.txt
答案 7 :(得分:0)
与 Mark Setchell's answer 类似,您也可以使用带有显式分隔符的 xargs
:
ls | xargs -I% wc -l %
然后 xargs
不会明确地将所有输入发送到 wc
,而是一次发送一个操作数行。