是否可以链接 tr 命令以避免管道中出现多个 tr 进程?

是否可以链接 tr 命令以避免管道中出现多个 tr 进程?

我有一堆 txt 文件,我想以小写形式输出它们,仅按字母顺序输出,每行一个单词,我可以tr在管道中使用多个命令来完成此操作,如下所示:

tr -d '[:punct:]' <doyle_sherlock_holmes.txt | tr '[:upper:]' '[:lower:]' | tr ' ' '\n'

是否可以在一次扫描中完成此操作?我可以编写一个 C 程序来执行此操作,但我觉得有一种方法可以使用trsedawk来执行此操作perl

答案1

您可以组合多个翻译(涉及重叠的区域设置相关集的复杂情况除外),但不能将删除与翻译组合起来。

<doyle_sherlock_holmes.txt tr -d '[:punct:]' | tr '[:upper:] ' '[:lower:]\n'

两次调用tr可能比一次调用更复杂的工具更快,但这很大程度上取决于输入大小、不同字符的比例、工具的实现tr和竞争工具、操作系统、数量核心数量等

答案2

是的。您可以tr在 ASCII 语言环境中执行此操作(无论如何,对于 GNU 来说tr,这是它唯一的权限)。您可以使用 POSIX 类,也可以通过八进制数引用每个字符的字节值。您也可以跨范围分割它们的转换。

LC_ALL=C tr '[:upper:]\0-\101\133-140\173-\377' '[:lower:][\n*]' <input

上面的命令会将所有大写字符转换为小写,完全忽略小写字符,并将所有其他字符转换为换行符。当然,最后你会得到大量的空行。在这种情况下,挤压重复开关可能很有用,但如果将其与to转换tr -s一起使用,那么最终也会挤压大写字符。这样它仍然需要第二个过滤器,例如......[:upper:][:lower:]

LC... tr ... | tr -s \\n

...或者...

LC... tr ... | grep .

...所以它最终比这样做要方便得多...

LC_ALL=C tr -sc '[:alpha:]' \\n <input | tr '[:upper:]' '[:lower:]'

...它将-c按顺序将字母字符的补码压缩成单个换行符,然后在管道的另一侧进行从上到下的转换。

这并不是说这种性质的范围没有用。像这样的东西:

tr '\0-\377' '[1*25][2*25][3*25][4*25][5*25][6*25][7*25][8*25][9*25][0*]' </dev/random

...可以非常方便,因为它将输入字节转换为其值的扩频范围内的所有数字。不要浪费,不要想要,你知道。

另一种进行转换的方法可能涉及dd.

tr '\0-\377' '[A*64][B*64][C*64][D*64]' </dev/urandom |
dd bs=32 cbs=8 conv=unblock,lcase count=1

dadbbdbd
ddaaddab
ddbadbaa
bdbdcadd

因为dd可以同时进行unblocklcase转换,所以甚至可以将大部分工作交给它。但是,只有当您能够准确预测每个字的字节数时,这才真正有用 - 或者至少可以预先用空格填充每个字以达到可预测的字节数,因为unblock会占用每个块末尾的尾随空格。

答案3

以下是一些方法:

  • GNUgreptr:查找所有单词并将其变为小写

    grep -Po '\w+' file | tr '[A-Z]' '[a-z]'
    
  • GNU grep 和 perl:如上所述,但 perl 处理小写转换

    grep -Po '\w+' file | perl -lne 'print lc()'
    
  • perl:找到所有字母字符并以小写形式打印它们(感谢@steeldriver):

    perl -lne 'print lc for /[a-z]+/ig' file
    
  • sed:删除所有非字母或空格的字符,用小写版本替换所有字母字符,并用换行符替换所有空格。请注意,这假设所有空白都是空格,没有制表符。

    sed 's/[^a-zA-Z ]\+//g;s/[a-zA-Z]\+/\L&/g; s/ \+/\n/g' file
    

相关内容