可以链接 tr 命令以避免管道中的多个 tr 进程吗?

tle*_*man 11 sed awk perl tr

我有一堆 txt 文件,我想输出它们小写,只有字母和每行一个单词,我可以tr在这样的管道中使用多个命令来完成:

tr -d '[:punct:]' <doyle_sherlock_holmes.txt | tr '[:upper:]' '[:lower:]' | tr ' ' '\n'
Run Code Online (Sandbox Code Playgroud)

是否可以在一次扫描中完成此操作?我可以编写一个 C 程序来做到这一点,但我觉得有一种方法可以使用tr, sed,awk或来做到这一点perl

Gil*_*il' 9

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

<doyle_sherlock_holmes.txt tr -d '[:punct:]' | tr '[:upper:] ' '[:lower:]\n'
Run Code Online (Sandbox Code Playgroud)

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


mik*_*erv 5

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

LC_ALL=C tr '[:upper:]\0-\101\133-140\173-\377' '[:lower:][\n*]' <input
Run Code Online (Sandbox Code Playgroud)

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

LC... tr ... | tr -s \\n
Run Code Online (Sandbox Code Playgroud)

...或者...

LC... tr ... | grep .
Run Code Online (Sandbox Code Playgroud)

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

LC_ALL=C tr -sc '[:alpha:]' \\n <input | tr '[:upper:]' '[:lower:]'
Run Code Online (Sandbox Code Playgroud)

...-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
Run Code Online (Sandbox Code Playgroud)

...可能非常方便,因为它将输入字节转换为值的扩展频谱上的所有数字。不要浪费,不要,你知道。

另一种进行转换的方法可能涉及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
Run Code Online (Sandbox Code Playgroud)

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