トップ > Linuxらしい使い方を覚える >
プロセス置換でコマンドの実行結果をファイルとして渡す

  

コマンドの実行結果をファイルとして渡す "プロセス置換" とは

この記事で紹介するのは "プロセス置換" と呼ばれるシェルの機能です。 プロセス置換は、コマンドの実行結果を別のコマンドにファイルとして渡すことができる機能です。

ここでは "2つのディレクトリの内容を比較する" という作業を、プロセス置換を使って実施してみます。 まず最初にプロセス置換を使わない作業例を紹介し、次にプロセス置換を使った作業例を紹介します。

  
"2つのディレクトリの内容を比較する" とは、2つのディレクトリに置かれているファイルの比較です。 ファイルの内容を比較することはせず、あくまでのファイル名での比較を行います
  
比較に使用するのは diff コマンドです。 diff コマンドは 2つのファイルを比較して差分を表示します。

実施する手順は以下の通りです。

  1. ホームディレクトリの下に testdir ディレクトリを新たに作成する
  2. testdir ディレクトリの下に2つのディレクトリ dir1 と dir2 を作成する
  3. dir1 と dir2 のそれぞれのディレクトリにいくつかのファイルを作成する
  4. ディレクトリ dir1 と dir 2 のファイル一覧をプロセス置換を使わずに比較する
  5. ディレクトリ dir1 と dir 2 のファイル一覧をプロセス置換を使って比較する

比較用のディレクトリおよびファイルを準備する

では始めましょう。 まずは、ディレクトリおよびファイルを準備します。 端末を開き、キーボードから cd ; mkdir testdir と入力して、Enterキーを押してください。


cd ; mkdir testdir

 
  
先頭の cd コマンドはホームディレクトリに戻るためのものです。

以下のようにホームディレクトリの下に testdir ディレクトリを作成します。

taro@myhostname:~$ cd ; mkdir testdir
taro@myhostname:~$

では次に、testdir ディレクトリの下に dir1 と dir2 ディレクトリを作成します。 キーボードから mkdir testdir/dir1 testdir/dir2 と入力して、Enterキーを押してください。


mkdir testdir/dir1 testdir/dir2

 

以下のように dir1 と dir2 の2つのディレクトリをまとめて作成します。

taro@myhostname:~$ mkdir testdir/dir1 testdir/dir2
taro@myhostname:~$

では、2つのディレクトリが作成されたことを確認しておきましょう。 キーボードから ls -l testdir と入力して、Enterキーを押してください。


ls -l testdir

 

以下のように2つのディレクトリが作成されていることがわかります。

taro@myhostname:~$ ls -l testdir
合計 8
drwxrwxr-x 2 taro taro 4096  6月 21 15:22 dir1
drwxrwxr-x 2 taro taro 4096  6月 21 15:22 dir2
taro@myhostname:~$

必要なディレクトリの準備は終わりました。 続いて dir1 と dir2 ディレクトリの下にいくつかのファイルを作成します。 中身はどうでもいいため、どのファイルも空の状態で作成します

過去の記事で解説したように、空のファイルを作成するには touch コマンドを使います。 キーボードから touch testdir/dir1/a と入力して、Enterキーを押してください。


touch testdir/dir1/a

 
  
touch コマンドは空のファイルを作成するためのコマンドではなく、ファイルやディレクトリの最終変更日時を更新するためのコマンドです。 ファイルが存在しない場合に限り、ファイルを作成してから最終変更日時を更新します。

以下のように dir1 ディレクトリの下に a というファイルを作成します。

taro@myhostname:~$ touch testdir/dir1/a
taro@myhostname:~$

では、dir1 ディレクトリの内容を確認してみましょう。 キーボードから ls -l testdir/dir1 と入力して、Enterキーを押してください。


ls -l testdir/dir1

 

以下のようにファイル a が作成されていることが確認できます。

taro@myhostname:~$ ls -l testdir/dir1
合計 0
-rw-rw-r-- 1 taro taro 0  6月 21 16:54 a
taro@myhostname:~$

続いて、同じく dir1 ディレクトリに、b と c の2つのファイルを作成します。 b と c の2つファイルをまとめて作成しましょう。 キーボードから touch testdir/dir1/b testdir/dir1/c と入力して、Enterキーを押してください。


touch testdir/dir1/b testdir/dir1/c

 

以下のように2つのファイルをまとめて作成します。

taro@myhostname:~$ touch testdir/dir1/b testdir/dir1/c
taro@myhostname:~$

では、dir1 ディレクトリの内容を確認してみましょう。 キーボードから ls -l testdir/dir1 と入力して、Enterキーを押してください。


ls -l testdir/dir1

 

以下のように b と c というファイルも作成されています。

taro@myhostname:~$ ls -l testdir/dir1
合計 0
-rw-rw-r-- 1 taro taro 0  6月 21 16:54 a
-rw-rw-r-- 1 taro taro 0  6月 21 17:07 b
-rw-rw-r-- 1 taro taro 0  6月 21 17:07 c
taro@myhostname:~$

このように dir1 ディレクトリには a b c という3つのファイルが作成されました。 dir1 ディレクトリはこれで準備完了です


続いては dir2 ディレクトリへのファイルの作成です。 こちらのディレクトリには a b zz の3つのファイルを作成します

なお、3回に分けて作成することはぜず、1回のコマンド入力で3ファイルを一気に作成します。 今回は "ブレース展開" で記述してみましょう。 キーボードから touch testdir/dir2/{a,b,zz} と入力して、Enterキーを押してください。


touch testdir/dir2/{a,b,zz}

 
  
echo {1,2,9} は echo 1 2 9 と同じ意味になります。
  
echo {1..4} のように記述することもできます。 この場合には echo 1 2 3 4 と同じ意味になります。

以下のように3ファイルをまとめて作成します。

taro@myhostname:~$ touch testdir/dir2/{a,b,zz}
taro@myhostname:~$

このようにブレース展開を利用することで、キード入力にかかる手間を減らすことができます。

では、dir2 ディレクトリの内容を確認しましょう。 キーボードから ls -l testdir/dir2 と入力して、Enterキーを押してください。


ls -l testdir/dir2

 

以下のように a b zz の3つのファイルが作成されています。

taro@myhostname:~$ ls -l testdir/dir2
合計 0
-rw-rw-r-- 1 taro taro 0  6月 21 17:34 a
-rw-rw-r-- 1 taro taro 0  6月 21 17:34 b
-rw-rw-r-- 1 taro taro 0  6月 21 17:34 zz
taro@myhostname:~$

このように dir2 ディレクトリには a b zz という3つのファイルが作成されています。 これで dir2 ディレクトリの準備も終わりました。

プロセス置換を使わない比較

では、dir1 と dir2 のファイル一覧を diff コマンドを使って比較しましょう。 プロセス置換は使わずに比較します。

diff コマンドは、ファイルとファイルを比較するためのコマンドです。 よって、dir1 と dir2 のファイル一覧をそれぞれ事前にファイルに保存しておく必要があります

まずは dir1 のファイル一覧をファイルへ保存しましょう。 キーボードから ls testdir/dir1 > list1 と入力して、Enterキーを押してください。


ls testdir/dir1 > list1

 

以下のように dir1 ディレクトリのファイル一覧をファイル list1 に保存します。

taro@myhostname:~$ ls testdir/dir1 > list1
taro@myhostname:~$

続いては dir2 のファイル一覧のファイルへの保存です。 キーボードから ls testdir/dir2 > list2 と入力して、Enterキーを押してください。


ls testdir/dir2 > list2

 

以下のように dir2 ディレクトリのファイル一覧をファイル list2 にリダイレクトします。

taro@myhostname:~$ ls testdir/dir2 > list2
taro@myhostname:~$

これで dir1 と dir2 のファイル一覧をそれぞれファイルへ保存することができました

では diff コマンドで2つのファイルを比較してみましょう。 キーボードから diff list1 list2 と入力して、Enterキーを押してください。


diff list1 list2

 
  
"DIFFerence" から連想して覚えましょう。

以下のように2つのファイルの差分が表示されます。

taro@myhostname:~$ diff list1 list2
3c3
< c
---
> zz
taro@myhostname:~$

なお、出力結果の 3c3 は、3行目から3行目が変更されていることを表しています。 中央の記号 c が変更(Change)を意味します。

< c は 最初のファイル(list1) の当該行の内容が c であることを示しています。 同様に > zz は 2つ目のファイル(list2) の当該行の内容が zz であることを示しています。

- 中央の記号の意味 -
記号 意味
a 追加(Append)
c 変更(Change)
d 削除(Delete)

ではここで、少し脱線して comm コマンドを紹介したいと思います。 commコマンドもファイルを行単位で比較するためのコマンドですが、diff コマンドとは出力形式が異なります。

キーボードから comm list1 list2 と入力して、Enterキーを押してください。


comm list1 list2

 
  
"Common" から連想して覚えましょう。

以下のように結果が3列で表示されます

taro@myhostname:~$ comm list1 list2
        a
        b
c
    zz
taro@myhostname:~$

左の列には c のみが表示されていますが、この列には最初のファイル(list1) にのみ存在する行が表示されます。 中央の列には zz のみが表示されていますが、この列に表示されるのは2つ目のファイル(list2) にのみ存在する行です。 右の列には両方のファイルに存在する行(a と b)が表示されます。

comm コマンドでは特定の列の表示を抑制することができます。 オプション -1 で左の列を、-2 で中央の列を、-3 で右の列を非表示にすることができます。

試しに右の列(両方のファイルに含まれる行)を非表示にしてみましょう。 キーボードから comm -3 list1 list2 と入力して、Enterキーを押してください。


comm -3 list1 list2

 

以下のように共通する行が表示されなくなりました。

taro@myhostname:~$ comm -3 list1 list2
c
    zz
taro@myhostname:~$
  
comm -12 のように複数の列を非表示にすることもできます。

さらに脱線してしまいますが cmp コマンドも紹介しておきます。 cmp コマンドは2つのファイルを文字の単位で比較するコマンドです。 違う箇所を見つけたら、その場所を表示して即座に終了します。 差分や相違点は表示しません

キーボードから cmp list1 list2 と入力して、Enterキーを押してください。


cmp list1 list2

 
  
"CoMPare" から連想して覚えましょう。

以下のように違いを見つけた場所が表示されます。

taro@myhostname:~$ cmp list1 list2
list1 list2 異なります: バイト 5、行 3
taro@myhostname:~$

このように cmp コマンドでも2つのファイルを比較することができます。 違うかどうかだけを知りたいのなら diff コマンドや comm コマンドよりも cmp コマンドの方が使い勝手がいいです。


プロセス置換を使わない比較の解説はこれで終わりです。 続いては、プロセス置換を使った比較方法の解説に移りますが、その前に file1 と file2 を削除しておきましょう

過去の記事で解説したように、ファイルを削除するためのコマンドは rm コマンドです。 キーボードから rm list1 list2 と入力して、Enterキーを押してください。


rm list1 list2

 

以下のようにファイル list1 と list2 を削除します。

taro@myhostname:~$ rm list1 list2
taro@myhostname:~$

プロセス置換を使った比較

では、いよいよ本題のプロセス置換を使った比較です。 プロセス置換を使うことで、コマンドの実行結果を別のコマンドにファイルとして渡すことができます。

では、やってみましょう。 キーボードから diff <(ls testdir/dir1) <(ls testdir/dir2) と入力して、Enterキーを押してください。


diff <(ls testdir/dir1) <(ls testdir/dir2)

 

以下のようにファイルへ保存する方法と同じ結果を得ることができます。

taro@myhostname:~$ diff <(ls testdir/dir1) <(ls testdir/dir2)
3c3
< c
---
> zz
taro@myhostname:~$

このようにプロセス置換を使うことで、ファイルへ保存する手間を省くことができます

なお、

<(ls testdir/dir1)

という記述は、ls testdir/dir1 の結果をファイルとして渡すという意味です。 つまり、

ls testdir/dir1

の実行結果と、

ls testdir/dir2

の実行結果がそれぞれファイルとして diff コマンドに渡されました。 このようにコマンドの実行結果を別のコマンドにファイルとして渡す機能がプロセス置換です。


では、最後に後始末を行いましょう。 ホームディレクトリの下の testdir ディレクトリを削除します。

キーボードから rm -r testdir と入力して、Enterキーを押してください。


rm -r testdir

 

以下のように testdir ディレクトリを下位のファイルやディレクトリと一緒に削除します。

taro@myhostname:~$ rm -r testdir/
taro@myhostname:~$
  
  

まとめ

diff コマンド、comm コマンド、cmp コマンドを使うことで、2つのファイルを比較することができます。 diff コマンドと comm コマンドは行単位で比較し、cmp コマンドは文字単位で比較します。

操作/コマンド 説明
diff file1 file2 2つのファイル file1 と file2 を行単位で比較して差分を表示する
comm file1 file2 2つのファイル file1 と file2 を行単位で比較する
cmp file1 file2 2つのファイル file1 と file2 を文字単位で比較する

シェルにはプロセス置換と呼ばれる機能があり、コマンドを "<(" と ")" で囲むことで実行結果をファイルとして渡すことができます。

操作/コマンド 説明
command <(subcommand) subcommand の実行結果をファイルとして command に渡す
メニュー