我如何用`wc -l`获得单行?


12

我添加了一个git别名,以提供历史记录中特定文件的行数:

[alias]
lines = !lc() { git ls-files -z ${1} | xargs -0 wc -l; }; lc

但是,wc -l报告的是多个总计,因此,如果我有超过10万行,它将报告它们的总计,然后继续。这是一个例子:

<100k线(所需输出)

$ git lines \*.xslt
  46 packages/NUnit-2.5.10.11092/doc/files/Summary.xslt
 232 packages/NUnit-2.5.10.11092/samples/csharp/_UpgradeReport_Files/UpgradeReport.xslt
 278 total

> 100k行(必须通过管道传输到grep "total"

$ git lines \*.cs | grep "total"
 123569 total
 107700 total
 134796 total
 111411 total
  44600 total

我如何从而wc -l不是一系列小计中获得真实的总数?


根据stackoverflow.com/questions/2501402/…的问题是xargs,而不是wc。我仍然对如何解决它感兴趣,并且答案中没有很好的解决方案。
Ehryk 2014年

3
您的wc支持版本是否支持该--files0-from选项?然后,您可以做{ git ls-files -z ${1} | wc -l --files0-from=- ; }
Mark Plotnick 2014年

@MarkPlotnick我认为这应该是一个答案。
terdon

不。wc: unrecognized option '--files0-from=-'
Ehryk 2014年

Answers:


12

尝试一下,为此道歉:

cat *.cs | wc -l

或者,用git:

git ls-files -z ${1} | xargs -0 cat | wc -l

如果您实际上希望输出看起来像wc带有单个计数和总和的输出,则可以使用awk将各个行相加:

git ls-files -z ${1} | xargs -0 wc -l |
awk '/^[[:space:]]*[[:digit:]]+[[:space:]]+total$/{next}
     {total+=$1;print}
     END {print total,"total"}'

wc如果您觉得很重要,那将不会很好地进行排列。为此,您需要读取整个输入并将其保存,计算总计,然后使用总计来计算字段宽度,然后再使用该字段宽度来打印记住的行的格式化输出。像家庭装修项目一样,awk脚本从未真正完成过。

(请热心的编辑者注意:awk如果有一个文件的名称以“ total”开头和一个空格开头,则第一个条件的正则表达式;否则,条件可能会更简单$2 == "total"。)


可以,但是只输出总计(git ls-files -z ${1} | xargs -0 cat | wc -l)。但是,我错过了wc -l提供的每个文件的行数,就像上面的第一个示例一样。有什么办法可以在这里获得两全其美吗?
Ehryk 2014年

或者,如果这太困难了,那么如何进行开关以使它分解呢:只给出总数,否则就给出每个文件的正常wc以及总输出?
Ehryk 2014年

@Ehryk:您可以这样做两次,一次是grep -v删除总行数,一次是我建议获取总行数。或者,您也可以尝试在已编辑的答案中使用awk解决方案
rici 2014年

+1:“像家庭装修项目一样,awk脚本从未真正完成过。”
Ehryk 2014年

那就像一个魅力。我的最终结果:git ls-files -z ${1} | xargs -0 wc -l | awk '/^[[:space:]]*[[:digit:]]+[[:space:]]+total$/{next} {total+=$1;print} END {print "\n Total:",total,"lines"}'
Ehryk 2014年

7

如果您正在运行Linux,则wc可能来自GNU Coreutils,并且可以--files0-from选择读取一个文件(或stdin),该文件包含任意长的NUL终止文件名列表。在GNU Coreutils的WC文件说,“这是非常有用的,当文件名的名单很长,所以它可能超过命令行长度的限制。在这种情况下,在运行通过xargs的厕所是不可取的,因为它将该列表成片,使WC打印每个子列表的总数,而不是整个列表的总数。”

所以试试这个:

lc() { git ls-files -z ${1} | wc -l --files0-from=- ; } 

编辑:由于您wc是上个千年的人,并且没有该选项,因此,这是一种更可移植的解决方案,假设您拥有awk和没有任何名为“ total”的文件。它将过滤的输出wc,忽略任何total行,而是将它们加总并在最后打印出总计。

我不知道的一件事是,git别名实现是否会对$1和和$2内部单引号引起问题,需要将其原样传递给awk

lc() {
  git ls-files -z ${1} |
  xargs -0 wc -l |
  awk 'BEGIN { total=0; } { if (NF==2 && $2 == "total") total += $1; else print; } END { print total, "total"; }' ;
}

我不是Linux,它在Git的bash提示符的Git的Windows msysgit.github.io(msysgit)。
Ehryk 2014年

好。那么xargswc您正在运行的来自Cygwin?您可以粘贴的输出wc --version吗?
2014年

它们并非来自完整的cygwin安装:$ wc --version wc (GNU textutils) 2.0 Written by Paul Rubin and David MacKenzie. Copyright (C) 1999 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Ehryk

Windows可执行文件已满,C:\Program Files (x86)\Git\bin\wc.exe
Ehryk 2014年

@Ehryk Msysgit是Linux工具的端口,但是它倾向于具有旧版本,因此可能没有--files0-from
吉尔(Gilles)'所以

4

问题是xargs将命令分为多个运行,因此wc每次都报告总数。您有一些选择,可以按原样进行操作并解析wc输出:

git ls-files -z ${1} | xargs -0 wc -l | awk '/total/{k+=$1}END{print k,"total"}';

您可以整理文件:

git ls-files -z ${1} | xargs -0 cat | wc -l

或者,您可以xargs完全跳过(从此处改编):

unset files i; while IFS= read -r -d $'\0' name; do 
 files[i++]="$name"; 
done < <(git ls-files -z ${1} ) && wc -l "${files[@]}"

但是,如果您的文件列表比ARG_MAX长,那将会中断。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.