grepコマンドが条件文で機能しない

grepコマンドが条件文で機能しない

すべてのファイル名を繰り返し、特定の文字(「o」など)を含むファイル名のみを印刷するbashスクリプトがあります。

私がしたこと:

command=`ls -l`
for file in $command
do
  if $file | grep 'o' ;
  then
  echo "$file"
  fi
done

これはうまくいきません。行に「コマンドが見つかりません」と表示されます。

if $file | grep 'o' ;

私はここでいくつかの異なる答えを見つけました、彼らは私と同じことをしています。つまり、括弧のない if 文、同じ構文などです。

私は何を見落としていますか?

答え1

$file | grep -ofileと値で指定されたコマンドを実行します。管路grepしかし、これは明らかにあなたが望むものではありません。

以下を含むファイルを一覧表示する場合o

値は実行するコマンドではなく、file入力ファイルであることを意味します。grepだから入力が必要です。リダイレクト、パイプではありません。

if grep 'o' <"$file"

grepコマンドラインでファイル名を受け取らない場合は、標準入力から読み込みます。コマンドラインからファイル名を渡すこともできます。これは同じことを行います。

if grep 'o' -- "$file"

二重引用符が使用される理由と--2番目のアプローチの理由については、次を参照してください。スペースやその他の特殊文字が原因でシェルスクリプトが停止するのはなぜですか?

出力を抑制するには、オプションを使用するか、grep出力-qをにリダイレクトします/dev/null

if grep -q 'o' <"$file"

または

if grep 'o' <"$file" >/dev/null

スクリプトの別の問題は、command=`ls -l`変数をファイル名のリストではなくcommandコマンドの出力に設定することです。ls -lまだ覚えているならスペースやその他の特殊文字が原因でシェルスクリプトが停止するのはなぜですか?、保存できないことを覚えておきますリストファイル名ひも変数:すべてのファイル名が混在しています。ここにはより悪い問題があります。権限、日付などのジャンクがあります。シェルスクリプトからファイル名のリストを取得するには、次のようにします。ワイルドカードパターン

for file in *
do
  if grep -q 'o' <"$file"
  then
    echo "$file"
  fi
done

これらはすべて次のとおりです。

grep -l 'o' -- *

名前に以下を含むファイルを一覧表示するにはo

この機能はシェルに組み込まれており、ワイルドカードパターン。パターンは*o*含まれているファイル名と一致するため、oそれらを一覧表示する必要があります。

ls -l -- *o*

--ファイル名の1つがで始まる場合は必須です。-そうしないと、lsファイル名がオプションとして解釈される可能性があります。

これが使い方の学習練習であり、grepファイル名を入力として渡したい場合は、そのgrepコマンドを使用する必要がありますecho

echo "$file" | grep 'o'

このechoコマンドは、一部のファイル名を破損する可能性があります。安全を維持するにはを使用してくださいprintf。これに関する詳細と二重引用符の使用については、以下を参照してください。スペースやその他の特殊文字が原因でシェルスクリプトが停止するのはなぜですか?

printf '%s\n' "$file" | grep 'o'

上記のように、出力は解析されませんls

for file in *
do
  if printf '%s\n' "$file" | grep -q 'o'
  then
    printf '%s\n'
  fi
done

ファイル名に改行文字が含まれていない場合。

for file in *
do
  printf '%s\n' "$file" | grep 'o'
done

ここでもループは意味がありません。

printf '%s\n' *o*

一致するファイル名を別の行に印刷します。grepこれは正規表現が必要で、シェルのワイルドカードパターンが十分でない場合にのみ必要です。

答え2

を実行しようとしています$file。代わりにこれをエコーする必要があります。

# ...
if echo "$file" | grep 'o' ;
# ...

grepはすでにファイル名を印刷しているため、その名前をミュートする必要があります(たとえば、grep -q 'o'またはgrep 'o' >/dev/null)。

また、あなた-lに渡すlsいいえやりたいです。ls -l一致させるファイル名と属性を印刷します。

また、どのファイルでも機能させるには引用符を使用する必要がありますが、これが問題の原因ではありません。

PS:他の人が指摘したように、ls最初は使用しないでください。

答え3

ls出力にまったく依存しないでください。lsスクリプトに使用せずに人間に優しい出力を表示するように設計されています。以下の例をご覧ください。

for f in ./*
  do 
   if [[ $f = *o* ]]; then 
    printf '%s\n' "$f"
   fi
 done

答え4

まず、これはgrepに何かをパイプする方法ではありません。また、それ一般的に言えば条件からコマンドを分離し、戻りコードのみを確​​認するより良い形式と見なされます。

次のようなものが完璧に動作します。

command=`ls -l`
for file in "$command"
do
  echo "$file" | grep 'o'
  if [ $? -eq 0 ]; then
    echo "$file"
  fi
done

関連情報