在`wc -l`输出中抑制摘要信息

时间:2016-12-29 18:32:40

标签: linux bash shell wc

我使用命令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"。

8 个答案:

答案 0 :(得分:3)

然而是sed解决方案!

1。简短快捷

由于总计在最后一行上传,$d是用于删除最后一行的命令。

wc -l $directory-path/*.txt | sed '$d'

2。添加标题行:

wc -l $directory-path/*.txt | sed '$d;1ilines total'

不幸的是,没有对齐。

3。对齐:将左列格式化为11个字符宽度。

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

4。但是,如果您的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 wcman -s1p wc)显示
如果指定了多个输入文件操作数,则应写入与其他行格式相同的附加行,除了应写入total(在POSIX语言环境中)而不是路径名和总数每栏的内容应酌情书写。这样的附加行(如果有的话)写在输出的末尾。

你说Total line是第一行,手册说明了最后一行,其他wc根本没有显示。删除第一行或最后一行是危险的,所以我grep -v行总数(在POSIX语言环境中......),或者只是grep所有其他行的斜杠:

wc -l $directory-path/*.txt | grep "/"

答案 4 :(得分:0)

不是最优化的方式,因为您可以使用catechocoreutilsawksedtac的组合,等,但这会让你想要你想要的:

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,而是一次发送一个操作数行。