すべてのファイル名を繰り返し、特定の文字(「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 -o
file
と値で指定されたコマンドを実行します。管路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