web-dev-qa-db-ja.com

パイプラインで複数のtrプロセスを回避するために、trコマンドをチェーンできますか?

私はたくさんのtxtファイルを持っています。それらを小文字のアルファベットと1行あたり1ワードだけで出力したいのですが、次のようなパイプラインでいくつかのtrコマンドを使用して実行できます。

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

これを1回のスキャンで実行することは可能ですか?これを行うCプログラムを作成することもできますが、trsedawkまたはPerlを使用してそれを行う方法があるように感じます。

11
tlehman

複数の翻訳を組み合わせることができます(ロケール依存セットの重複を伴​​う複雑なケースを除く)。ただし、削除と翻訳を組み合わせることができません。

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

trへの2回の呼び出しは、より複雑なツールへの1回の呼び出しよりも高速になる可能性がありますが、これは、trの実装に応じて、入力サイズ、さまざまな文字の比率に大きく依存します。オペレーティングシステム、コア数などの競合ツール.

はい。 ASCIIロケール(つまり、GNU trの場合、その唯一の目的の一種)でtrを使用してそれを行うことができます)。POSIXクラスを使用することも、各文字のバイト値を8進数で参照することもできます。変換を範囲間で分割することもできます。

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

上記のコマンドは、すべての大文字を小文字に変換し、小文字を完全に無視し、他のすべての文字を改行に変換します。もちろん、それから大量の空白行が発生します。その場合は、tr-squeeze repeatsスイッチが役立つ可能性がありますが、[:upper:]から[:lower:]への変換と一緒に使用すると、大文字の絞り込みも行われます。その方法では、それでも次のような2番目のフィルターが必要です...

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

...または...

LC... tr ... | grep .

...そのため、実行するよりもはるかに不便になります...

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

...これは、アルファベット文字の-complementをシーケンスごとに1つの改行に圧縮し、パイプの反対側で上部から下部への変換を行います。

それは、その性質の範囲が役に立たないと言っているのではありません。次のようなもの:

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の両方の変換を同時に実行できるため、多くの作業をそれに渡すことも可能です。ただし、これは、1ワードあたりのバイト数を正確に予測できる場合、または少なくとも各ワードの前にスペースを埋め込んで予測可能なバイトカウントにできる場合にのみ役立ちます。unblockは各ブロックの末尾にある末尾のスペースを使用するためです。

4
mikeserv

ここにいくつかのアプローチがあります:

  • GNU grepおよびtr:すべての単語を検索して小文字にします

    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
    
4
terdon