4

Perl のダイヤモンド演算子を bash でシミュレートする慣用的な方法はありますか? ダイヤモンド演算子を使用すると、

script.sh | ...

入力用に stdin を読み取り、

script.sh file1 file2 | ...

入力として file1 と file2 を読み取ります。

もう 1 つの制約は、自分のスクリプトへの入力以外の目的で script.sh の stdin を使用したいということです。以下のコードは、上記の file1 file2 ... の場合に必要なことを行いますが、標準入力で提供されるデータの場合は行いません。

command - $@ <<EOF
some_code_for_first_argument_of_command_here
EOF

私は Bash ソリューションを希望しますが、どの Unix シェルでも問題ありません。

編集:明確にするために、script.shの内容は次のとおりです。

#!/bin/bash
command - $@ <<EOF
some_code_for_first_argument_of_command_here
EOF

Perl でひし形演算子が機能するようにこれを機能させたいのですが、現在のところ、引数としてのファイル名しか処理できません。

編集2:うまくいくことは何もできません

cat XXX | command

コマンドの標準入力はユーザーのデータではないためです。コマンドの標準入力は、ヒアドキュメントの私のデータです。ユーザー データをスクリプトの stdin に入れたいのですが、スクリプト内のコマンド呼び出しの stdin にすることはできません。

4

7 に答える 7

6

確かに、これは完全に実行可能です:

#!/bin/bash
cat $@ | some_command_goes_here

ユーザーは、引数なし (または「-」) でスクリプトを呼び出して、標準入力または複数のファイルから読み取ることができます。これらはすべて読み取られます。

これらのファイルの内容を (たとえば、行ごとに) 処理したい場合は、次のようにすることができます。

for line in $(cat $@); do
    echo "I read: $line"
done

編集:役立つコメントのおかげで、ファイル名のスペースを処理するように変更$*されました。$@

于 2009-04-09T19:14:07.993 に答える
4

ちょっと安っぽいけどどう?

cat file1 file2 | script.sh
于 2009-04-09T17:25:06.680 に答える
2

私は (他のみんなと同じように) ここでの目標が正確に何であるかについて少し混乱しているようです。まず、ファイルのリスト (コマンド ラインで指定) または通常の stdin からスクリプトを読み取るという比較的単純な目標です。

if [ $# -gt 0 ]; then
  exec < <(cat "$@")
fi
# From this point on, the script's stdin is redirected from the files
# (if any) supplied on the command line

注: $@ の二重引用符の使用は、ファイル名に変な文字 (スペースなど) が含まれる問題を回避するための最良の方法です。ここで使用している <() トリックは、bash のみの機能です。バックグラウンドで cat を起動して、コマンド ラインで指定されたファイルからデータをフィードします。次に、exec を使用して、スクリプトの stdin を cat からの出力に置き換えます。

...しかし、それはあなたが実際に望んでいるようには見えません。あなたが本当に望んでいるように見えるのは、提供されたファイル名またはスクリプトの stdinを引数としてスクリプト内のコマンドに渡すことです。これには、逆のプロセスが必要です。つまり、スクリプトの stdin を、コマンドに名前を渡すことができるファイル (実際には名前付きパイプ) に変換します。このような:

if [[ $# -gt 0 ]]; then
  command "$@" <<EOF
here-doc goes here
EOF
else
  command <(cat) <<EOF
here-doc goes here
EOF
fi

これは <() を使用して、スクリプトの stdin を cat を介して名前付きパイプに洗濯し、それを引数として command に渡します。一方、コマンドの標準入力はヒアドキュメントから取得されます。

さて、それはあなたがやりたいことだと思いますが、提供されたファイルからスクリプトの stdin をリダイレクトし、stdin をスクリプト内のコマンドに渡すという、あなたが求めているものとはまったく異なります。これは、上記の手法を組み合わせることで実現できます。

if [ $# -gt 0 ]; then
  exec < <(cat "$@")
fi

command <(cat) <<EOF
here-doc goes here
EOF

...とはいえ、なぜあなたが実際にこれをやりたいのかはわかりません。

于 2009-04-11T19:32:17.090 に答える
1

最初の引数を取得して何かを実行し、指定されたファイルから読み取るか、ファイルがない場合は stdin から読み取りますか?

個人的には、「-a value」構文を使用して getopt を使用して引数を示し、あいまいさを解消することをお勧めしますが、それは私だけです。getoptsなしで bash で行う方法は次のとおりです。

firstarg=${1?:usage: $0 arg [file1 .. fileN]}
shift
typeset -a files
if [[ ${#@} -gt 0 ]]
then
  files=( "$@" )
else
  files=( "/dev/stdin" )
fi
for file in "${files[@]}"
do
  whatever_you_want < "$file"
done

引数が指定されていない場合、?: 演算子は終了します。それをつかんだ後、引数を1つシフトしてから、残りの引数をファイルリストとして使用するか、他に引数がない場合はbashの特別なファイルハンドル「/dev/stdin」を使用します。

「ファイルが指定されていない場合は /dev/stdin を使用する - それ以外の場合はコマンドラインでファイルを使用する」という部分はおそらくあなたが探しているものだと思いますが、コードの残りの部分は少なくともコンテキストに役立ちます。

于 2009-04-10T15:07:53.413 に答える
1

Perl のひし形演算子は、基本的にすべてのコマンド ライン引数をループし、それぞれをファイル名として扱います。各ファイルを開き、行ごとに読み取ります。ほぼ同じことを行うbashコードを次に示します。

for f in "$@"
do
   # Do something with $f, such as...
   cat $f | command1 | command2
   -or-
   command1 < $f
   -or-
   # Read $f line-by-line
   cat $f | while read line_from_f
   do
      # Do stuff with $line_from_f
   done
done
于 2009-04-09T18:58:09.373 に答える
0

少し安っぽいですが、これはどうですか:

if [[ $# -eq 0 ]]
then
  # read from stdin
else
  # read from $* (args)
fi

行ごとに読み取って処理する必要があり (可能性が高い)、同じコードを 2 回コピーして貼り付けたくない場合 (可能性が高い)、スクリプトで関数を定義し、行を 1 つずつ渡します。 -1 つをこの関数に渡し、それらをその関数で処理します。

于 2009-04-09T19:13:16.873 に答える
0

スクリプトで``cat @*' を使用しないのはなぜですか? 例えば:

x=`cat $*`
echo $x
于 2009-04-09T19:17:37.657 に答える