はじめに
シェルスクリプトで困るのが入力に癖のあるコマンド。
別のプロンプトを起動して操作する形式だったり、対話形式が必須だったり、ファイル指定形式でないと受け付けなかったり。
(SQL*Plusなどが典型的。sqlplus user/password @hogehoge.sql
みたいな)
そのようなコマンドを含むシェルスクリプトを1ファイルにまとめる方法をまとめてみた。多くの環境で動くと思うけど一応Bash念頭。
あるコマンドの標準出力を別の標準入力にする場合
これはご存知の皆様も多いかと。まとめて示す。
- パイプ(pipe): あるコマンドの次にパイプライン(|←コレ)を置き、続けてコマンドを置くと前のコマンドの標準出力を後のコマンドの標準入力に渡すことができる。
書き方としてはこんな感じ。
outputcommand | inputcommand
具体例としては
$ echo -e "hoge\nhuga" | grep "hoge" hoge
- リダイレクト (redirect): あるコマンドの次に小なり記号(<←コレ)を置き、続けてファイルを置くと後のファイルを前のコマンドの標準入力に渡すことができる。 書き方としてはこんな感じ。
command < file
具体例としては
$ cat test.txt hoge huga $ grep hoge < test.txt hoge
別プロンプトがシェルからの入力を受け付ける場合(SQL*Plusなど)
ヒアドキュメント(Here document)を使う。リダイレクトの複数行版みたいなもの。
「<<ある文字列」から「ある文字列」の間までの改行を含む文字列を標準入力に流し込むことができる。「ある文字列」はなんでもいい。
これが威力を発揮するのは例えばSQL*Plusみたいな「制御のためにOSのシェルではないプロンプトを起動する」ケース。
例えばOracleDBの起動シェルスクリプトを作成する場合、以下のようにstartdb.sh、startdb.sqlの2ファイルを用意する必要がある。
ただ数行レベルかつDBを起動するという目的が同じスクリプトをわざわざ分けたくないと考える。
% cat startdb.sh #!/bin/sh sqlplus / as sysdba exit 0 % cat startdb.sql startup quit
よってヒアドキュメントを使用する。具体例を以下に示す。ここでは「ある文字列」をHEREとしている。先に説明した通りどんな文字列でもいい。
% cat startdb1.sh #!/bin/sh sqlplus / as sysdba <<HERE startup quit HERE exit 0
これで1ファイルのままstartdb.sh、startdb.sql分の働きをすることができる。
なおヒアドキュメントの詳細は以下のとおり。
<<HERE
: 文字列の解釈はシェルに順ずる。つまりヒアドキュメント内に$hogeという文字列があればそれはシェル関数であり、hoge関数内の文字列に置き換わる。<<'HERE'
: 文字列をそのまま扱う。つまりヒアドキュメント内に$hogeという文字列があればそのまま$hogeという文字列として渡される。<<(タブ文字)HERE
: 行頭のタブ文字は無視する。インデントをしている場合に適する。
対話形式コマンドを自動入力する場合
商用ソフト等でまれにある対話形式が必須で、かつパイプやリダイレクト(ヒアドキュメント)を受け付けないようなコマンドを自動化したいケース。
コマンドexpect
コマンドを使う。メジャーなdistroで入ってるイメージないので追加インストールが必要になるかも。
使い方は説明長くなりそうなので省略する。気が向いたら追記するかも。
echoコマンドの結果をファイルとして扱う(プロセス置換)
ややマニアックな方法?かも。あるコマンドの結果をファイルとして扱う方法。
ちょっとややこしいので具体例を示す。
$ cat read_test.sh #!/bin/sh while read line do echo $line done < $1 exit 0 $ cat file.txt aaa bbb ccc $ ./read_test.sh file.txt aaa bbb ccc $ ./read_test.sh <(echo -e "aaa\nbbb\nccc") aaa bbb ccc $
説明を加える。
ファイルを読み込むコマンド(read_test.sh)を呼び出す処理をしたい(./read_test.sh file.txt)が、
そのためにわざわざ別ファイル(file.txt)をつくりたくないとする。
その場合はファイルの中身に相当する処理をechoコマンド結果として実行している。
さいごに
これまでシェルスクリプトをX年書いてきてぶつかったパターンはだいたいこんな感じ。
特にラスト2つは結構調べた記憶があるので今後の備忘録。