Stdinをファイルにリダイレクトするかどうかを決定するためにこれを試みました:
[ ...some condition here... ] && input=$fileName || input="&0"
./myScript < $input
しかし、変数$ inputが「&0」の場合、bashはそれをファイル名として解釈するため、機能しません。
しかし、私はただ行うことができました:
if [ ...condition... ];then
./myScript <$fileName
else
./myScript
問題は、。/ myScriptが実際には長いコマンドラインであり、複製したくない、またはそのために関数を作成したくないことです。これもそれほど長くないためです(価値がありません)。
次に、これを行うことが私に起こりました:
[ ...condition... ] && input=$fileName || input= #empty
cat $input | ./myScript
しかし、そのためには、もう1つのコマンドとパイプ(つまり、サブシェル)を実行する必要があります。
もっと簡単で効率的な方法はありますか?
まず、stdinは1(stdout)ではなく、ファイル記述子0(ゼロ)です。
ファイル記述子を複製するか、次のように条件付きでファイル名を使用できます。
[[ some_condition ]] && exec 3<"$filename" || exec 3<&0
some_long_command_line <&3
表示されているコマンドは、いずれかの条件がfalseの場合、2番目のexec
を実行することに注意してくださいor最初のexec
は失敗します。失敗の可能性を望まない場合は、if
/else
を使用する必要があります。
if [[ some_condition ]]
then
exec 3<"$filename"
else
exec 3<&0
fi
ただし、最初のリダイレクトが失敗した場合(条件がtrueになった後)、ファイル記述子3からのその後のリダイレクトは失敗します。
標準入力は、特殊なデバイスファイル/dev/stdin
で表すこともできるため、ファイル名として使用すると機能します。
file="/dev/stdin"
./myscript < "$file"
(
if [ ...some condition here... ]; then
exec <$fileName
fi
exec ./myscript
)
サブシェルで、条件付きでstdinをリダイレクトし、スクリプトを実行します。
いかがですか
_function runfrom {
local input="$1"
shift
case "$input" in
-) "$@" ;;
*) "$@" < "$input" ;;
esac
}
_
標準入力を表すためにマイナス記号を使用しましたが、これは多くのUnixプログラムにとって伝統的なものだからです。
今あなたは書く
_[ ... condition ... ] && input="$fileName" || input="-"
runfrom "$input" my-complicated-command with many arguments
_
コマンドを引数としてとるこれらの関数/コマンド(xargs(1)
など)は非常に便利で、うまく構成できます。
注意する場合は、「eval
」と最初のアイデアを使用できます。
[ ...some condition here... ] && input=$fileName || input="&1"
eval ./myScript < $input
ただし、「myScript」は実際には複雑なコマンド呼び出しであると言います。スペースを含む可能性のある引数が含まれる場合は、 'eval
'の使用を決定する前に十分に注意する必要があります。
率直に言って、 'cat
'コマンドのコストについて心配することは、おそらく問題の価値はありません。ボトルネックになることはまずありません。
通常のUnixフィルターのように機能するようにmyScript
を設計することはさらに優れています-機能するファイルが1つ以上指定されていない限り(たとえば、cat
またはgrep
など)、標準入力から読み取ります。その設計は長く健全な経験に基づいているため、このような問題に対処する必要がないようにエミュレートする価値があります。
eval
を使用:
#! /bin/bash
[ $# -gt 0 ] && input="'"$1"'" || input="&1"
eval "./myScript <$input"
このmyScript
の簡単な代用
#! /usr/bin/Perl -lp
$_ = reverse
次の出力が生成されます。
$ ./myDemux myScript pl- lrep/nib/rsu /!# esrever = _ $ $ ./myDemux foo oof bar rab baz zab
入力のスペースも処理することに注意してください。
$ ./myDemux foo\bar eman eht ni ecaps a htiw Elif
入力をmyScript
にパイプダウンするには、 プロセス置換 を使用します。
$ ./myDemux <(md5sum /etc/issue) eussi/cte/ 01672098e5a1807213d5ba16e00a7ad0
次のように出力を直接パイプしようとすると、
$ md5sum/etc/issue | ./myDemux
ephemient's answer にはこの欠点はありませんが、ターミナルからの入力を待ってハングします。
わずかな変更により、望ましい動作が生成されます。
#! /bin/bash
[ $# -gt 0 ] && input="'"$1"'" || input=/dev/stdin
eval "./myScript <$input"
人々はあなたに非常に長いスクリプトを見せます、しかしあなたはbashトラップを受け取ります:)あなたはすべてをbashで引用しなければなりません。たとえば、&0という名前のリストファイルが必要です。
filename = '&0' #right ls $ filename #wrong!これは$ filenameを置き換え、&0 ls "$ filename" #rightを解釈します
別の、スペースを含むファイル。
filename = 'スペースのあるファイル' ls $ filename #wrong、最初と最後のスペースをbashでカットし、withとスペースの間にある複数のスペースを減らしますls "$ filename" righ
スクリプトでも同じです。どうか変更してください:
./myScript < $input
に
./myScript < "$input"
そのすべて。 bashにはより多くのトラップがあります。同じ理由で「$ file」も引用することをお勧めします。解釈できないスペースやその他の文字は常に問題を引き起こします。
/ dev/stdinはどうですか?これは、stdinをリダイレクトして何かを実際のstdinに出力したい場合にのみ使用できます。
したがって、スクリプトは次のように表示されます。
[ ...some condition here... ] && input="$fileName" || input="&0"
./myScript < "$input"