この bash 行で何が起こっているのかを段階的に説明してくれる人はいますか? 私はここに来たばかりで、このコードがどのように機能するかを理解しようとしています。特に次の点についてですecho
:
read char; echo -e "YES\nNO\n" | grep -i $char
答え1
行のコマンドはchar
、おそらくユーザーから対話的に文字列を変数に読み込みます。
+パイプラインはecho
、grep
入力された文字列が肯定的であるかどうかを判断しようとします。これは、大文字YES
と小文字を区別NO
せずに、単語 と を入力された文字列 (入力された文字列をパターンとして使用) と照合することによって行われます。ユーザーが単語 に含まれる大文字または小文字の文字、あるいは部分文字列を入力した場合、YES
結果は になります。YES
また、文字列 に含まれる大文字または小文字の文字、あるいは部分文字列を入力した場合NO
、結果は になりますNO
。 のように入力すると、maybe
空の出力になります。
このアプローチの欠点は、例えばユーザーが と入力した場合、と の.
両方YES
が とNO
一致することですgrep
。 はドットを任意の文字に一致する正規表現として扱います。$char
の呼び出しでは は引用符で囲まれていないgrep
ため、ユーザーが などのシェルグロブパターンを入力として入力した場合、マシンに対するサービス拒否攻撃を引き起こす可能性もあります/*/*/*/*/../../../../*/*/*/*
(例は から引用)。bash/POSIX シェルで変数を引用符で囲み忘れた場合のセキュリティへの影響)。また、たとえば次のように入力すると、コマンドの出力が混乱する可能性があります-r -o -e . /
(これは、非バイナリ ファイルのすべての文字を、そのファイルのパス名を先頭に付けた 1 行に出力します)。
あなたが示したコードは、ユーザー入力を本質的に何かとして使用している点で「奇妙で異常」です。コードつまり、ユーザー入力をパターン、静的テストデータこの変数パターンに対してテストします。これは、ユーザーからの入力を受け取り、この変数データを静的パターンに対してテストするという通常のやり方とは逆のことです。
次のようなコードを使用するのが一般的です。
read -p 'Yes/[N]o: ' yesno
if [[ $yesno == [Yy]* ]]; then
# code for affirmative
else
# code for non-affirmative
fi
上記のコードは、ユーザーから文字列を読み取り、それが ay
またはY
文字で始まるかどうかをテストします。そうである場合はステートメントの最初のブランチif
が実行されますが、そうでない場合はデフォルトでブランチが実行されますelse
。
もちろん、単語全体YES
、大文字と[Yy][Ee][Ss]
小文字を区別しない一致をテストしたり、検証付きの適切な入力ループを実行したりすることもできます。
while true; do
read -p 'Yes/No: ' yesno
if [ "$yesno" = Yes ] || [ "$yesno" = No ]; then
break
fi
echo 'Please enter "Yes" or "No"' >&2
done
# $yesno is either Yes or No here
(または類似のもの)。
上記の両方のサンプル コードでは、ユーザーの入力がパターンとしてではなく、データとしてのみ使用されていることに注意してください。
元のコマンドを少し慣用的な(ただし機能的に異なり、おそらく完全ではない)ものに最小限書き換えると、次のようになります。
read yesno; printf '%s\n' "${yesno^^}" | grep -i -w -E 'yes|no'
ユーザーが またはと入力した場合、これは大文字YES
のまたは を返します。これは、たとえば に対してユーザーが だけでなく何か他のものを入力する必要があるため、機能的に異なります。NO
yes
no
e
yes
答え2
さて、各コマンドを順番に見ていきましょう。
read char
これは標準入力 (通常はキーボードですが、間接ファイルまたはパイプ ストリームの場合もあります。以下を参照) から読み取り、受信したデータを という名前の変数に格納しますchar
。
echo -e "YES\nNO\n"
echo
は、提供されたパラメータを標準出力(通常は端末)に表示します。-e
スイッチを使用すると(多くの場合、常にではありませんが、echo
一貫した実装に関しては問題があります)、e
特定の文字をエスケープして基本的な書式設定を行うことができます。 この場合は を使用していますが\n
、これはエスケープされた でありn
、これは ewline の省略形ですn
。
grep -i $char
grep
指定された入力を検索して、指定されたパターンに一致するものがあるかどうかを確認するツールです。スイッチは、大文字と小文字を区別しない検索を-i
行うように指示します。i
|
コマンドecho
とコマンドの間のはgrep
「パイプ」です。これにより、最初のコマンドの出力が 2 番目のコマンドの入力に接続されます。つまり、 はgrep
このコーパスで変数 の内容に反映されたパターンを検索することになりますchar
。
YES
NO
このコマンド シーケンスの実際の結果は、提供された入力を確認することです (変数名に基づいて 1 つの文字であると想定されますが、これはチェックされません)。この文字が 、 、 、 、 、または の場合Y
、E
出力S
はy
にe
なりs
ますYES
。この文字がN
、 、O
、n
または の場合o
、出力は になりますNO
。ただし、(たとえば) 入力がyo
または の場合ne
、何も出力されません。
前述のように、入力が 1 文字であるという前提はチェックされません。これは、示されているコマンド シーケンスの例における唯一のアンチパターンではありません。たとえば、変数は引用符で囲まれておらず、正規表現ツール ( grep
) は、入力が正規表現ワイルドカードに対してスクリーニングされることなく使用されています。
答え3
「文字」(文字列)が から読み込まれます/dev/stdin
。つまり、それを入力します。
次に、 2 行が/dev/stdout
. コンソールに出力されます。
そして、パイプ (「|」) を介して、大文字と小文字を区別しない入力バージョンが grep されます。
つまり、「bar」と入力すると、何も出力されずに終了しますが、「y」と入力すると、「YES」の行が出力され、おそらく「Y」が強調表示されます。