• ベストアンサー

シェルのリダイレクトとパイプについて

シェルのリダイレクトとパイプについての質問です. リダイレクトでコマンドの標準出力をファイルに指定した後に, パイプを置いて,もう一つコマンドを並べたとき, 後の方のコマンドの標準入力はどうなるのでしょうか? 例えば, ls >outfile |cat ならば, catの標準入力には,何も入ってこないと思うのですが, これを実行すると,lsの結果がoutfileに書き込まれ, 次のプロンプトが表示されます. 普通,catを引数なしで実行すると, EOFが入力されるまで,入力待ちになると思うのですが, こうならないのは,シェルがcatの標準入力にEOFを入力したからだと 考えていいのでしょうか. よろしくお願いします. (質問の意味が分かりにくければご指摘下さい.)

質問者が選んだベストアンサー

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4846/10257)
回答No.2

パイプ処理の順序としては、細かい説明は省きますが、パイプが作られ、次にプロセスが作られ、各プロセスでリダイレクトの処理が行われ、最後にそれぞれプログラムが起動されます。 リダイレクトが優先されるように見えるというのはそういうことです。 ls > outfile | cat だと、前半の > のリダイレクト処理の時点で、パイプの入り口がcloseされます。入り口がクローズされたパイプの出口を読もうとすると、EOFが返るので、cat は終了します。これはシェルの機能と言うより、OSのパイプの機能です。 ls | cat < infile 同じく、後半のリダイレクト処理の時点で、パイプの出口がcloseされます。出口がクローズされたパイプの入り口に書き込もうとすると、SIGPIPE というシグナルが発生します。 (ls ; echo "ls status=$?" >&2 ) | cat < infile を実行すると、 ls status=141 と表示されるはずです。141 というステータスは、プロセスがSIGPIPEで終了したと言うことです。 なお、シェルによってclose等ののタイミングが異なるようで、sh bash以外では上記と異なる場合があります。

goopth
質問者

お礼

>パイプ処理の順序としては、細かい説明は省きますが、パイプが作られ、次にプロセスが作られ、各プロセスでリダイレクトの処理が行われ、最後にそれぞれプログラムが起動されます。 とても参考になりました. (ls ; echo "ls status=$?" >&2 ) | cat < infile という方法も教えていただき有り難うございます.

その他の回答 (1)

  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.1

ls > outfile | cat のcatは標準入力からの入力を一切受け取りません。考え方としてはEOFしかこなかったと考えていただいても結構ですが、正確にはそういう事(標準入力からの入力がない)です。 ls | cat < infile こちらは ls < infile | cat と見比べていただけたら大体意味が分かるのではないでしょうか。ためしに cat -n < infile | cat -n とやってみてはどうでしょうか。  ただ、ご存知の通りパイプとリダイレクトは「シェルの機能」です。なので、パイプやリダイレクトはこうあるべきという規定はありますが実装依存という事になります。実際に、FreeBSD 8.0-RELEASEのcshで ls | cat < infile としたところ、Ambigous input redirectというエラーになりました。同じくFreeBSD 8.0-RELEASEのパッケージからインストールしたbashではリダイレクトが優先されました。

goopth
質問者

お礼

理解できました. cshとbashでの違いも参考になりました. 有り難うございます.

関連するQ&A

  • シェルでリダイレクトができない

    bashを使っているのですが、 シェルの中で、 ./実行ファイル hoge1 hoge2 > hoge.txt という感じで二つの引数を使って動作する実行ファイルの標準出力を、リダイレクトしたいです。 ですが、テキストに出力をリダイレクトできません。 こんな感じの書き方でリダイレクトできないもんなんでしょうか? 教えて欲しいです。 よろしくお願いします。

  • Kシェルのリダイレクト

    Kシェルのリダイレクト シェル初心者で申し訳ございませんが、ご教授いただけたら幸いです。 やりたいこと  xxx.kshの実行ログを出力したい。 出力したいログは、以下コマンド実行時に標準出力されるログをファイルへ落としたい。 尚、実際の実行コマンドは、ksh -xは入力しません。 $ ksh -x ./xxx.ksh 上記コマンドを実行すると、詳細なログが表示されるのですが、ファイルへ落としたいと思います。 分かりづらいかも知れませんが、宜しくお願い致します。

  • シェル変数とパイプ

    シェルの変数にパイプを入れた文字列(コマンド)を格納し、それを実行したいのですが、「|」がただの文字として扱われているようでうまく実行できません。 どのように記述すれば、パイプとして認識してくれるのでしょうか? 次のようなことをやりたいのですが、このようにエラーになってしまいます。 # setenv cmd "ls | grep test" # $cmd ls: |: そのようなファイルやディレクトリはありません ls: grep: そのようなファイルやディレクトリはありません ls: test: そのようなファイルやディレクトリはありません

  • パイプの使いかたについて

    linux初心者です。 パイプの使いかたについて教えて下さい。 パイプを使うことでパイプ前の結果をパイプ後に引きわたし、パイプ後にあるコマンドを実行できる、というようなことはネットで調べました。 ls -l | lessのような。。(ls結果をlessで表示する。) ここで質問なのですが、 grep photo | illust sample.txt としたとき、sample.txtのなかからphotoまたはillustに、マッチする行を抽出するという意味でよいのでしょうか? 自分で検証した限りではそのようにみえました。 ただ、そうだとしたとき、パイプの意味がよくわからなくなってしまいます。 パイプ前でコマンドを実行、その結果を引数にしてパイプ後でコマンドを実行するというように考えないほうがよいのでしょうか? すみませんが、使用方法について教えてください。

  • リダイレクトとパイプについて教えてください。

    リダイレクトとパイプについて教えてください。 test.exeというコンソールプログラムがあり、 実行すると、1秒置きに10回コンソール画面に"!!!!!!"を表示して終了するプログラムとします。 これをリダイレクトで test.exe > result.txt とした場合、1秒置きに"!!!!!!"がresult.txtに追加されることを期待しているのですが、 10秒後にtest.exe終了時に一気に、"!!!!!!"が10個吐き出されます。 1秒おきに(リアルタイムで)、"!!!!!!"を吐き出すようにはできないでしょうか。 標準入力を受け取ってファイルに吐き出すプログラムresult.exeをつくり、 これをパイプで test.exe | result.exe としても、リアルタイム吐き出しができず、同じ結果でした。

  • パイプ

    C++からはじめたので、パイプについてよくわかりません。 DOSで dir | more とか、UNIXで ls | more とかやると、前のコマンドの標準出力を、後ろのコマンドの標準入力に渡すというのは、わかるんですが、これはDOS上、UNIX上でのことですよね。 プログラムToプログラムで、パイプを使うには、どうしたらよいのでしょうか。

  • PERLとシェルについて

    コマンドプロンプトで入力されたPERLコマンドはシェルのプログラムによってカーネルに引き渡されてカーネルがPERLのプログラムにそのコマンドを実行させて、その結果をカーネル→シェルへと引き渡されてコマンドプロンプトに表示されるのでしょうか?

  • 名前付きパイプを使い文字列をブロードキャスト

    名前付きパイプを利用して、文字列をブロードキャストしたいと考えています。 --- シェル1$ cat > fifo --- シェル2$ cat fifo --- シェル3$ cat fifo --- のような状態で、シェル 1 で hello と入力し、Enter キーを押下すると、シェル 2 およびシェル 3 に hello と表示させたいのですが、実際にはシェル 3 (後から fifo を開いたシェル)にしか印字されません。 シェル 1 にて入力を終了(EOF送信)すると、シェル 2 、シェル 3 ともにファイルがクローズされ、cat が終了しているので、EOF は両方ともにブロードキャストされているようにも見え、動きが不可解です。 Q1) 名前付きパイプ fifo は、その名のとおり、「早い者勝ち」でデータを取得した方にしかデータが流れないんでしょうか。 Q2) その場合、親子関係なくプロセス間で、複数のプロセスに対して同一の文字列をブロードキャスト方法は、どのようにすればスマートでしょうか。 一度、通常ファイルに出力を書き込み、全プロセスが文字列を取得した事を監視してキューを削除する、みたいな方法は可能だと思いますが、これよりも良い方法があればお教えください。

  • シェルの引数チェックについて

    HP-UNIX シェルで指定された引数の桁数のチェックや入力値のチェックを 行いたいと思っております。 自分なりに調べた所、awkコマンドを使用して、lengthや正規表現 でチェックできそうなのですが、シェルで指定された引数をどの ようにしてチェックすればよいのかがわかりません。 例)aaa.sh 引数1 引数2   ⇒aaa.shの中で、$@等で上記のチェックを行う???  イメージとしては、   ・if (length($1) == 10) ・$1!~/[a-zA-Z0-9]/  でも、aaa.shの中で、awkの使用方法がわかりません。 awkを使用する以上、ls -l | awk ~~~ のように、 一度、引数をファイルに出力してから、grepとパイプ機能を使用 する?しか方法はないでしょうか。 (実行環境で、パーミッションの設定でシェルを実行できない 為、上記の方法を試すには到っていません・・・パーミッションについて も、まだ理解が乏しい為。) シェルスクリプトを触り出して、まだ間もない事もあり、可能な のかどうかも判断できない状況ですが、ご存知の方がいらっしゃ いましたら、ご教授頂ければと思います。  

  • <Linux>restoreコマンドのリダイレクトについて

    以下の内容でrestoreコマンドによる テープの内容チェックを自動で走らせています。 restore -ivf /dev/nst0 <<EOF >> $LOG ls >> $LOG EOF 以上のシェルの場合、restore -ivf /dev/nst0の結果は $LOGに出力されるのですが、lsの結果が反映されません。 デバックモードで動かしてみてもエラーになっている様子もありませんでした。 restore -ivf /dev/nst0 <<EOF >> $LOG ls EOF 以上で実行するとlsの結果が画面には出力可能です。 この結果を$LOGに出力させるにはどのようにしたらよろしいでしょうか?