Linux コマンドラインのコンセプト: パイプ機能と tr コマンド
この記事は、シリーズ 機械学習エンジニアのためのLinux の第6回です。
パイプ
前回の記事では、出力リダイレクトについて学んだ。
command > /path/to/file
のように記述することで、コマンドの実行結果をファイルとして保存することができる、という機能だ。
この記事では パイプ という機能と、パイプ機能でよく使う tr
というコマンドを紹介する。
パイプは、あるコマンドの出力を、別のコマンドの入力とする機能だ。 この機能を使うと、複数のコマンドを組み合わせて、いろいろな処理を組み立てられるようになる。
Linux のパイプラインの機能は、格闘ゲームのコンボ技と比較するとわかりやすいかもしれない。 格闘ゲームでは、プレイヤーが特定のボタンの組み合わせを素早く押すと、コンボとよばれる連鎖攻撃を放つことができる。 パンチやキックなどを連続させることで、単発の攻撃よりも強力なダメージを相手に与えられる。
同様に、コマンドラインのパイプ機能を使うと、1つのコマンドの出力が次のコマンドに入力され、次のコマンドの「引き金」となる。 この「コンボ」を成功させることで、単体のコマンドでは得られないさまざまな処理が実現できる。
📔 ノート
画面に表示されるコマンドの出力を、専門的には「標準出力(STDOUT)」という。 また、コマンドへの入力のことを「標準入力(STDIN)」という。
標準入出力については、別の記事で詳しく紹介したいと思う。
例題: ファイル一覧を CSV 形式で出力する
パイプ機能を利用する例として、次のようなケースを考えてみよう。
❓ 課題
次に示すディレクトリ構造をもつデータセットがあるとしよう。 (前回の記事で、例題として取り上げたデータセットと同じ構造だ)
/home/me/dataset |-train/ | |-speaker_a/ | | |-speech_0001.wav | | |-speech_0002.wav | | ... | |-speaker_b/ | |-speaker_c/ | | ... | `-speaker_z/ `-validation/ |-speaker_a/ | |-speech_1001.wav | |-speech_1002.wav | ... |-speaker_b/ |-speaker_c/ | ... `-speaker_z/
このデータセットの構成を、他のプログラム(Excel など)を使って分析したい。
そこで、データセット内に含まれるすべての
wav
ファイルのパスを、次のように 「trainまたはvalidation」、「話者」、「ファイル名」の3列をもつ CSV 形式で出力したい。 どうすればいいだろうか?train,speaker_a,speech_0001.wav train,speaker_a,speech_0002.wav ... validation,speaker_a,speech_1001.wav validation,speaker_a,speech_1002.wav ...
前回の記事では、find
コマンドを使うことでファイルパスを一覧表示できることを学んだ。
find
の出力は、次のようになる。
$ cd /home/me/dataset
$ find . -name '*.wav'
./train/speaker_a/speech_0001.wav
./train/speaker_a/speech_0002.wav
...
./validation/speaker_a/speech_1001.wav
./validation/speaker_a/speech_1002.wav
...
課題で示された CSV の内容と find
の出力を見比べると、それほど大きな違いがないことがわかると思う。
具体的には、find
の出力を次のように加工すれば、求められている CSV データが得られそうだ。
🤔 必要な処理
find
が出力したファイルパスの/
を,
に置換する- 行の先頭にある
./
(置換後は.,
になる) を削除する
これら2つの処理は、それぞれ tr
と cut
というコマンドを使うことで実現できる。
cut
の紹介は次回の記事に譲るとして、まずは tr
から見ていこう。
tr
コマンド
tr
は、テキストデータから特定の文字を置換したり、削除したりするコマンドだ。
このコマンドの基本的な使い方は、次のようになる。
tr <置換前の文字> <置換後の文字>
ここでは、find
の出力に含まれる /
を ,
に置換するので、次のようなコマンドになる。
tr / ,
置換機能のほかに、tr
には文字を削除する機能もある。
削除機能を使うには、-d
オプションを使う。
tr -d <削除したい文字>
例えば、出力から /
を削除したいならば、次のコマンドを実行すればいい。
tr -d /
ただ、このコマンドを単体で実行しただけでは、find
の出力を tr
で置換することはできない。
find
の出力と tr
の入力をつなげることで、こうした処理ができるようになる。
パイプ
find
の出力と tr
の入力を接続するのに必要となるのが、パイプ機能だ。
パイプの基本的な使い方は、次のようになる。
command_1 | command_2
このように、2つのコマンドの間を |
記号で区切ると、command_1
コマンドの出力が command_2
コマンドの入力に接続される。
早速、find
コマンドの出力を先ほど紹介した tr
の入力に接続してみよう。
具体的には、次のようなコマンドになる。
$ find . -name '*.wav' | tr / ,
.,train,speaker_a,speech_0001.wav
.,train,speaker_a,speech_0002.wav
...
.,validation,speaker_a,speech_1001.wav
.,validation,speaker_a,speech_1002.wav
...
これを、find
コマンド単体で実行した結果と比べてみよう。
$ find . -name '*.wav'
./train/speaker_a/speech_0001.wav
./train/speaker_a/speech_0002.wav
...
./validation/speaker_a/speech_1001.wav
./validation/speaker_a/speech_1002.wav
...
両者を比べると、find
の後ろに tr
コマンドを連結することで、/
という文字が ,
に置き換わっているのがわかると思う。
これが、文字列を置換するという tr
コマンドの効果だ。
もし /
を削除したい場合は、find
コマンドに tr -d /
をパイプ接続すればいい。
$ find . -name '*.wav' | tr -d /
.trainspeaker_aspeech_0001.wav
.trainspeaker_aspeech_0002.wav
...
.validationspeaker_aspeech_1001.wav
.validationspeaker_aspeech_1002.wav
...
フィルタコマンド
tr
コマンドは、これまで見てきた cd
や ls
などのコマンドと異なり、単体でコマンドを実行しただけでは何も起こらない。
置換・削除する文字列を引数として指定したうえで、入力データを与える必要がある。
tr
はこの入力データを加工して、その結果を出力することに特化しているわけだ。
Linux コマンドラインでは、tr
コマンドのように入力データを受け取って加工するコマンドがいくつかある。
例えば、sort
というコマンドはデータの並べ替えができる。
また、次回の記事で紹介する cut
コマンドでは、文字列の一部を抽出することが可能だ。
与えられたデータの加工に特化したこれらのコマンドは、フィルタコマンドとよばれる。
フィルタコマンドを find
のような通常のコマンドと組み合わせることで、さまざまな処理が実現できる。
まとめ
今回の記事では、Linux のパイプ機能と tr
コマンドについて紹介した。
パイプ機能は、GUI にないコマンドラインの大きな特徴の一つだ。 GUI のアプリケーションは操作方法や結果表示がそれぞれ異なり、複数のアプリケーションを連携させることは難しい場合が多い。 それに対して、CLI はパイプのようにプログラム間でデータを簡単に受け渡せる機能をもっており、多くのコマンドはテキスト形式での入出力に対応している。 これにより、いろいろなコマンドを連携させて「コンボ技」を構築することが簡単にできる。
今回はパイプと tr
コマンドを用いた文字列の置換について説明したが、この処理はパイプラインによって実現できる機能のほんの一部にすぎない。
次回は、find
、tr
と cut
という3つのコマンドをパイプで組み合わせた、より複雑な処理を取り上げよう。
これら3つのコマンドを組み合わせることで、例題で示した CSV データを出力できるようになる。
それでは、次回の記事をお楽しみに!
🎯 まとめ
- パイプ: あるコマンドの出力を、別のコマンドの入力とする機能
tr
: 入力されたテキストデータから、特定の文字を置換・削除するコマンド
tr / ,
: 入力されたデータの/
をすべて,
に置き換えるtr -d /
: 入力されたデータの/
をすべて削除するfind . -name '*.wav' | tr / ,
: 次の処理をするコマンド
- カレントディレクトリ以下にある、拡張子が
.wav
で終わるファイルを再帰的に検索する- 検索にヒットしたファイルパスに含まれる
/
を、すべて,
に置き換えて出力する
❓ 練習課題
- パイプを使って、次の処理をするコマンドを構築しよう。
pwd
の出力に含まれる/
という文字を、すべて\
に置き換えて出力するコマンド$ pwd /home/yumemio $ (下記のような出力になるコマンドを構築する) \home\yumemio ...
ls -l
の出力に含まれるx
という文字を、すべて@
に置き換えて出力するコマンド$ ls -l drwx------ 4 yumemio yumemio 4096 4月 29 12:35 snap drwxr-xr-x 2 yumemio yumemio 4096 4月 23 13:48 ダウンロード drwxr-xr-x 2 yumemio yumemio 4096 4月 23 13:48 テンプレート ... $ (下記のような出力になるコマンドを構築する) drw@------ 4 yumemio yumemio 4096 4月 29 12:35 snap drw@r-@r-@ 2 yumemio yumemio 4096 4月 23 13:48 ダウンロード drw@r-@r-@ 2 yumemio yumemio 4096 4月 23 13:48 テンプレート ...