web-dev-qa-db-ja.com

ヒアドキュメントや猫と組み合わせて出力リダイレクトをどのように使用しますか?

別のコマンドにパイプしたり、ファイルにリダイレクトしたりするスクリプトがあるとします(例ではshにパイプします)。私がbashを使用していると仮定します。

echoを使用してそれを行うことができます:

echo "touch somefile
echo foo > somefile" | sh

catを使用しても、ほぼ同じことができます。

cat << EOF
touch somefile
echo foo > somefile
EOF

しかし、 "EOF"を "EOF | sh"に置き換えると、それは単にヒアドキュメントの一部であると見なされます。

catがstdinからテキストを出力し、それを任意の場所にパイプするようにするにはどうすればよいですか?

64
strugee

これには複数の方法があります。最も単純なものはおそらくこれです:

cat <<EOF | sh
touch somefile
echo foo > somefile
EOF

別の、私の意見ではより良い構文です:

(
cat <<EOF
touch somefile
echo foo > somefile
EOF
) | sh

これも機能しますが、サブシェルはありません。

{
cat <<EOF
touch somefile
echo foo > somefile
EOF
} | sh

その他のバリエーション:

cat <<EOF |
touch somefile
echo foo > somefile
EOF
  sh

または:

{ cat | sh; } << EOF
touch somefile
echo foo > somefile
EOF

ところで、私はあなたの質問でのcatの使用が何か他のプレースホルダーであることを期待しています。そうでない場合は、次のように取り出します。

sh <<EOF
touch somefile
echo foo > somefile
EOF

これはこれに簡略化できます:

sh -c 'touch somefile; echo foo > somefile'

または:

sh -c 'touch somefile
echo foo > somefile'

パイピングの代わりに出力をリダイレクトする

sh >out <<EOF
touch somefile
echo foo > somefile
EOF

catを使用してecho test > outと同等のものを取得する:

cat >out <<EOF
test
EOF

複数のヒアドキュメント

( cat; echo ---; cat <&3 ) <<EOF 3<<EOF2
hi
EOF
there
EOF2

これは出力を生成します:

hi
---
there

これが起こっていることです:

  • シェルは( ... )を確認し、囲まれたコマンドをサブシェルで実行します。
  • 猫とエコーは十分に単純です。 cat <&3は、fd 3からリダイレクトされたファイル記述子(fd)0(stdin)でcatを実行するように言っています。つまり、fd 3からの入力を除外します。
  • (...)が開始される前に、シェルは2つのhereドキュメントのリダイレクトを確認し、fd 0(<<EOF)とfd 3(3<<EOF2)をパイプの読み取り側に置き換えます
  • 最初のコマンドが開始されると、シェルはEOFに達するまでstdinを読み取り、それを最初のパイプの書き込み側に送信します
  • 次に、EOF2と2番目のパイプの書き込み側で同じことを行います
103
ash

meowの使用はEOFと同じくらい有効であることを指摘したいだけです。

このスクリプトは、catという名前のファイルにMeow!を追加します。

#!/bin/sh
cat <<meow>> cat
Meow!
meow

catsとして保存し、chmod +x catsで実行可能にしてから、./catsで実行します。

$ ./cats
$ cat cat
Meow!
$ ./cats
$ cat cat
Meow!
Meow!

説明:

  • cat <<meowhere document構文です。文字列meowが見つかるまで、この行に続くテキストブロックを取得するようにスクリプトに指示します。次に、コンテンツが出力(またはパイプ)されます。
  • >> catは、catという名前のファイルにパイプします。
  • >の代わりに>>を使用すると、ファイルに追加するのではなく、ファイルを上書きします。
  • Meow!は、こちらのドキュメントの内容です。
  • meowは、hereドキュメントの終了マーカーです。内容は、>>を使用して、catに追加されます。

stdoutとファイルの両方にパイプする:

リクエストしたパイピングを行うために、ヒアドキュメントは必要ありません。

catはテキストを出力することもテキストを渡すこともできませんが、teeはあなたが求めているものと完全に一致します。

echo echo | tee tee

これにより、文字列echoが出力され、echoteeという名前のファイルに書き込まれます。

catを介して出力を渡すこともできます。これが要件の一部である場合は、次のいずれかを使用します。

echo echo | tee tee | cat </dev/stdin

あるいは単に:

echo echo | tee tee | cat

ファイルの内容:

$ cat tee
echo
1
Alexander