一个 Shell 脚本来模拟 wc 命令及其选项?



我们必须编写一个shell脚本程序,其工作原理类似于wc命令。 接收-l-c-w作为其选项。

抛开外壳脚本语法;我的问题是,我们可以使用sedgrepanything else来模拟wc -cwc -lwc -w的逻辑吗?如果是那如何?

IMP:不要在脚本中使用wc

可以通过将适当的-v变量设置为0来参数化的单个awk命令:

LC_ALL=C awk -v l=1 -v w=1 -v c=1 '
{ wc+=NF; cc+=1+length($0) }
END { printf "%st%st%sn", l ? NR : "", w ? wc: "", c ? cc : ""}
' file

注意:

  • 为简单起见,您总是得到 3 个t分隔的输出字段,其中未请求输出的字段为空;但是,修改它以模拟wc的输出行为并不难。

  • 正如choroba的grep答案中所解释的,如果你真的想计算字节(-c)而不是(可能是多字节)字符(-m),你必须在awk ...前面加上LC_ALL=C 

    • 要计算字符数(相当于wc -m),请删除上面的LC_ALL=C 
      警告:不幸的是,这不适用于 BSDawk,就像在 macOS 上一样,因为它不能识别 Unicode 并且总是计算字节数(尝试awk '{print length($0)}' <<<ü)。
  • wc -l严格计算n字符的数量,因此它不会在其输入的末尾计算不完整的行 - 缺少尾随n的行;相比之下,上面的awk命令确实计算该行(以及字节/字符计数中隐含的尾随换行符)。

  • 工作原理:

    • awkNF变量包含每个输入行上的字段数,其中行默认通过任意空格分隔为字段;换句话说:默认情况下,字段是单词。
    • $0是手头的输入行,其length()告诉您字符/字节数,并添加1以考虑行尾的n字符。
    • 请注意变量wccc如何初始化,因为awk隐式地将空/未定义的变量视为数字上下文中的0变量(例如使用复合运算符+=)。
    • NR包含当前从 1 开始的行号,在END块中等于输入行的总数。

使用 awk:

-l

awk 'END{print NR}' inFile

-w

awk '{words+=NF}END{print words}' inFile

-c

ls -l inFile | awk '{print $5}'

如果你可以使用grep,模拟行数很容易:只需计算匹配的事情总是发生多少次:

grep -c '^' filename

这应该输出与wc -l相同的输出(但如果文件不以换行符结尾,它可能会再报告一行)。

若要获取字数,可以使用以下管道:

grep -o '[^[:space:]]+' filename | grep -c '^'

您需要支持-o选项的grep,该选项将每个匹配的字符串打印到自己的行中。该表达式匹配所有非空格序列,将它们管道到我们在前面的情况中使用的序列中只是计算它们。

要获取字符数(wc -c),您可以使用

LC_ALL=C grep -o . filename | grep -c '^'

如果您的区域设置支持 UTF-8,则需要设置 LC_ALL,否则您将计wc -m.您需要将换行符的数量添加到输出编号中,因此

echo $(( $( grep -c '^' filename ) 
+ $( LC_ALL=C grep -o . filename | grep -c '^' ) ))

最新更新