grep
実行されたというコマンドに引数としてcmd
単語が含まれているかどうかを確認するために使用したいと思いますname
。(Bash の については知っていますが!*
、使用したくありません)。
という変数にコマンドがあるとしますprocess
。
最初は を試しましたecho $process | grep 'cmd name'
。これは 1 つの引数しか考慮しないため、十分に洗練されていません。
そこで、正規表現 を使って、これを最後の引数としてキャプチャできるかどうか試してみましたcmd .*(?= )name
。アイデアとしては、何でもキャプチャし、その後にスペースを入れ、その後にname
( の後にcmd
) を入れるというものです。しかし、これはうまくいきません。
私の目標は、これがうまくいけば、それがどの立場でも議論になるかを説明することです。
正規表現を使用してこれを実行するにはどうすればよいですか?
答え1
以下の回答では、 の使用を明示的に避けていますgrep
。コマンド ラインは個別の項目のリストであり、テキストの行としてではなく、そのように解析する必要があります。
コマンドとコマンドの引数の両方を1つの文字列に保持すると仮定します(配列を使用する方が良いでしょう。変数に保存されたコマンドを実行するにはどうすればよいですか?)の場合は、次のようにします。
process='cmd with "some arguments" and maybe name'
set -f
set -- $process
if [ "$1" != 'cmd' ]; then
echo 'The command is not "cmd"'
exit 1
fi
shift
for arg do
if [ "$arg" = 'name' ]; then
echo 'Found "name" argument'
exit
fi
done
echo 'Did not find "name" argument in command line'
exit 1
これはまずファイル名の生成を無効にします。$process
これは、unquoted を使用して別々の単語に分割したいためです。その文字列にファイル名のグロブ パターン ( など*
) が含まれていると、解析が混乱します。これは で行いますset -f
。
次に、位置パラメータを 内の単語に設定します$process
。その後、"$1"
である場合は、コマンド ラインの残りの部分でcmd
を探す必要があることがわかります。そうでない場合は、そこで停止します。name
shift
位置パラメータのリストから外れ、cmd
ループ内で引数を調べ始めます。各反復では、引数を文字列と比較するだけですname
。見つかった場合は、その旨を通知して終了します。
ループの最後で、name
引数が見つからなかったことがわかっているので、これを報告して失敗で終了します。
上記の例では、引数はsome arguments
次のように解析されることに注意してください。別文字列"some
と はarguments"
、コマンドとその引数を 1 つの文字列に格納しない理由の 1 つです。また、name
単一の引数 内の引数が検出されることになり"some name string"
、誤検知になります。
コマンドラインが配列に格納されている場合 (例bash
)、次のように実行できます。
process=( cmd with "some arguments" and maybe name )
if [ "${process[0]}" != 'cmd' ]; then
echo 'The command is not "cmd"'
exit 1
fi
for arg in "${process[@]:1}"; do
if [ "$arg" = 'name' ]; then
echo 'Found "name" argument'
exit
fi
done
echo 'Did not find "name" argument in command line'
exit 1
の展開は"${process[@]:1}"
配列全体になりますが、最初の項目 (コマンド名) は展開されません。
/bin/sh
(および、dash
さらにbash
および他の任意の POSIX シェル)の場合、上記はより簡潔になります。
set -- cmd with "some arguments" and maybe name
if [ "$1" != 'cmd' ]; then
echo 'The command is not "cmd"'
exit 1
fi
shift
for arg do
if [ "$arg" = 'name' ]; then
echo 'Found "name" argument'
exit
fi
done
echo 'Did not find "name" argument in command line'
exit 1
これは基本的に最初のコードと同じですが、コマンド ラインのすべての要素を 1 つのテキスト文字列に結合することはないため、すべての引数 (引用符など) が正しく処理されます。
答え2
bash について言及したので、もう 1 つのオプションはパターン マッチング演算子です=~
。
if [[ $process =~ ^cmd[[:space:]].*name([[:space:]]|$) ]]
then
_name_ was found as an argument to _cmd_
fi
これは、変数の内容が で始まりcmd
、その後にスペースが続き、その後に何かまたは何も続かず、その後に が続きname
、その後にスペースまたは行末が続くかどうかを確認します。