grepの結果をループ内の変数として保存するのに問題があります。
while read file;do
Server=$(echo $file | awk '{ print $1 }')
FDate=$(echo $file | awk '{ print $2 }')
ST=$(cat foobar | grep $Server | awk '{ print $3 }')
#ST=$(grep $Server foobar | awk '{ print $3 }')
echo "Server = $Server"
echo "FDate = $FDate"
echo "ST = $ST"
done < inputfile
最初のST varは、反復ごとに「Usage:grep [Option] ... Pattern [File]」出力を提供します。これは、コマンドが正しく読み取られていないことを意味します。
コメントアウトされた2番目のST変数は実際にスクリプト全体を中断し、エコーを試みると他のすべての変数が空になります。
これで、コマンドラインで同じことをしようとするとうまくいきます。
$ testme=$(cat foobar | grep Big | awk '{ print $3}'
$ echo "$testme"
tada
だから私の質問は、このgrepコマンドを変数に保存する方法です。パターンマッチングには可能な結果が1つしかないため、複数のマッチングについて心配する必要はありません。ただし、ループ内の各サーバーは、列3(tada、tada1、tada2)に異なる文字列を持つことができます。
編集する:
入力ファイルには、複数の列を含むサーバーのリストがあります。現在行の列1にリストされているサーバーをインポートし、foobarファイルから一致するものを検索し、列3から文字列を取得します。
「使用」メッセージが表示されるにもかかわらず、スクリプトが実際に機能していることがわかりました。入力ファイルの一部のサーバーエントリがfoobarファイルにまだ表示されていないため、grepに一致はありませんが、まだawkにパイプしようとする可能性があります。よくわかりません。
しかし、私はまだ「使用」メッセージを削除したいと思います。私の考えでは「set -opipelinefail」がうまくいくかもしれませんが、そうしない方が良いです。
答え1
while read file;do # 1
Server=$(echo $file | awk '{ print $1 }') # 2
FDate=$(echo $file | awk '{ print $2 }') # 3
ST=$(cat foobar | grep $Server | awk '{ print $3 }') # 4
#ST=$(grep $Server foobar | awk '{ print $3 }') # 5
grep
少なくとも検索パターンが必要です(またはそれに対応するオプションを提供するかオプション-e
)。したがって、空の場合は、4行と5行の引用符なしの内容-f
$Server
$Server
噴射(あなたも見ることができます いつ二重引用符が必要ですか?)、そして
- 行4
grep
にはパラメータはありません。必須パラメーターがない場合は、使用法の説明が印刷されます。 - 行5では、
grep
単一のパラメータを取得してfoobar
パターンにします。基本的には標準入力から読み込み、ループ内にはループと同じ標準入力があるので、そこからすべてを読みます。
さて、ループ全体を見ると、次の質問が考えられます。シェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?少なくともある程度単純化することができます。read
入力はフィールド自体に分割できるため、コマンド置換を削除できます。
これにより、おそらく値のいずれかまたは両方が空の場合に対処する必要があります。そして、awkも作業を実行できるので、grep
次のようにしましょう。
while read server fdate; do
if [ -z "$server" ] || [ -z "$fdate" ]; do
continue
fi
ST=$(awk < foobar -v server="$server" '$0 ~ server { print $3 }')
echo "server $server fdate $fdate ST $ST"
done < inputfile
(または最終的に何をしたいかに応じて、全体をawkプログラムに置き換えます。)
答え2
シェルwhileループgrep
(またはawk
どのこれはシェルループのコマンドと似ています。バラよりシェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?理由があります。簡単に言えば、シェルは他のプログラムにタスクを実行させること、リダイレクトとパイプを設定し、実際にタスクを実行している他のプログラムにファイル名とデータを提供するのに非常に熟練していますが、タスク自体を実行するのには不便です。シェルは遅く、変数を二重引用符で囲まないなどのユーザーエラーが発生しやすい(たとえば、$ Serverを引用できませんでした)。これが"$Server"
問題の直接の原因ですgrep
。とにかく、他の理由の1つは失敗したことです。 $ Serverに実際にawkの後に値が含まれていることを確認してください。
とにかく、短いスクリプトで必要なすべての操作を実行できますawk
。たとえば、
awk 'NR==FNR { fdates[$1] = $2 ; next}; # read first file into fdates array
$1 in fdates { # process second file
printf "Server = %s\nFDate = %s\nST = %s\n", $1, fdates[$1], $3;
}' inputfile foobar
英語で:
読む最初
fdates
ファイルを作成し、キーフィールド1(サーバー)と値フィールド2(FDate)という名前の連想配列に保存します。2番目のファイル(およびそれ以降のファイル)を読み取るときにサーバー名がfdatesのキーである場合は、必要な詳細を印刷します。
メモ:サーバー名を検索するファイルのフィールドが指定されていませんfoobar
。上記のスクリプトはフィールド1にあると想定していますfoobar
。別のフィールドにいる場合は、両方の行を変更します$1
($1 in fdates
そしてラインprintf
)に適応します。
サーバー名が次のような場合どこかに1行にfoobar
(つまり、一致する固定フィールド番号がない)、次のようにスクリプトを作成できます。
awk 'NR==FNR { fdates[$1] = $2 ; next};
{ for (server in fdates) {
if ($0 ~ server) {
printf "Server = %s\nFDate = %s\nST = %s\n", server, fdates[server], $3;
}
}' inputfile foobar
英語で:
読む最初ファイルを保存するには、キーがフィールド1(サーバー)で値がフィールド2(FDate)の連想配列に保存されます。
fdates
つまり、最初のバージョンと同じです。次に、ファイルの後続の行ごとに配列
fdates
の各要素を繰り返します。行の任意の場所にキー(サーバー名)と一致する正規表現がある場合は、必要な詳細が印刷されます。
fdates
2番目のバージョンは、含まれているすべてのサーバー名に対して正規表現一致を実行する必要があるため、最初のバージョンより少し遅くなります。各ワイヤーfoobar
。
どちらのバージョンもwhile readループよりはるかに高速で、awk
1に対して約3回の呼び出しを実行し、cat
ループを介して毎回ファイル全体を読み取りますgrep
。上記の各awkスクリプトは一度だけ呼び出され、一度だけfoobar
読む必要があります。inputfile
foobar