私はこれをしたい:
例として、$PID
からコマンド名を取得したいとします(これは単なる例であることに注意してください。プロセスIDからコマンド名を取得する最も簡単な方法を提案するわけではありません-私の本当の問題は、出力形式を制御できない別のコマンドにあります)。
ps
を実行すると、次の結果が得られます。
PID TTY TIME CMD
11383 pts/1 00:00:00 bash
11771 pts/1 00:00:00 ps
今、私はps | egrep 11383
をして、
11383 pts/1 00:00:00 bash
次のステップ:ps | egrep 11383 | cut -d" " -f 4
。出力は次のとおりです。
<absolutely nothing/>
問題は、cut
が出力を単一のスペースでカットし、ps
が2番目と3番目の列の間にスペースを追加してテーブルの類似性を保つため、cut
は空の文字列を選択することです。もちろん、cut
を使用して4番目のフィールドではなく7番目のフィールドを選択することもできますが、特に出力が可変で事前に不明な場合はどうすればわかりますか。
簡単な方法の1つは、tr
のパスを追加して、繰り返されるフィールド区切り文字を絞り出すことです。
$ ps | egrep 11383 | tr -s ' ' | cut -d ' ' -f 4
最も簡単な方法はawkを使用することだと思います。例:
$ echo "11383 pts/1 00:00:00 bash" | awk '{ print $4; }'
bash
tr -s ' '
オプションは、先頭のスペースを削除しないことに注意してください。列が右揃えの場合(ps
pidなど)...
$ ps h -o pid,user -C ssh,sshd | tr -s " "
1543 root
19645 root
19731 root
次に、最初の列である場合、これらのフィールドの一部に切り取りを行うと空白行が作成されます。
$ <previous command> | cut -d ' ' -f1
19645
19731
スペースを前に付けない限り、明らかに
$ <command> | sed -e "s/.*/ &/" | tr -s " "
さて、(名前ではなく)pid番号のこの特定の場合には、pgrep
という関数があります:
$ pgrep ssh
ただし、一般に、read
コマンドにはきちんとしたことがあるため、実際にはShell functionsを簡潔に使用することができます。
$ <command> | while read a b; do echo $a; done
読み取る最初のパラメーターa
は、最初の列を選択し、さらにある場合は、elsethingがすべてb
。その結果、列の数+ 1より多くの変数は必要ありません。
そう、
while read a b c d; do echo $c; done
その後、3列目が出力されます。私のコメントに示されているように...
パイプ読み取りは、呼び出し元のスクリプトに変数を渡さない環境で実行されます。
out=$(ps whatever | { read a b c d; echo $c; })
arr=($(ps whatever | { read a b c d; echo $c $b; }))
echo ${arr[1]} # will output 'b'`
そのため、@ frayserによる答えになります。これは、デフォルトでスペースに設定されているシェル変数IFSを使用して、文字列を配列に分割することです。ただし、Bashでのみ機能します。 DashとAshはサポートしていません。 Busyboxで文字列をコンポーネントに分割するのは本当に大変でした。単一のコンポーネントを取得して(awkを使用するなど)、必要なパラメーターごとにそれを繰り返すのは簡単です。しかし、同じ行で繰り返しawkを呼び出すか、同じ行でエコー付きの読み取りブロックを繰り返し使用することになります。効率的でもきれいでもありません。したがって、${name%% *}
などを使用して分割することになります。慣れている機能の半分以上がなくなっていれば、実際にはシェルスクリプトはあまり楽しくないので、いくつかのPythonスキルに憧れます。しかし、あなたはpythonでさえそのようなシステムにインストールされないと仮定することができ、それはそうではなかった;-)。
試してみる
ps |&
while read -p first second third fourth etc ; do
if [[ $first == '11383' ]]
then
echo got: $fourth
fi
done
Brianeggeのawkソリューションと同様に、Perlに相当するものを次に示します。
ps | egrep 11383 | Perl -lane 'print $F[3]'
-a
は自動分割モードを有効にし、@F
配列に列データを設定します。
データがスペース区切りではなくコンマ区切りの場合は、-F,
を使用します。
Perlは1ではなく0からカウントを開始するため、フィールド3が出力されます
配列変数を使用する
set $(ps | egrep "^11383 "); echo $4
または
A=( $(ps | egrep "^11383 ") ) ; echo ${A[3]}
正しい行(行番号6の例)の取得は頭と尾で行われ、正しい単語(単語番号4)はawkでキャプチャできます。
command|head -n 6|tail -n 1|awk '{print $4}'
あなたの命令
ps | egrep 11383 | cut -d" " -f 4
unwindが his answer で説明しているように、tr -s
を逃してスペースを絞ります。
ただし、awk
を使用することもできます。これは、これらのアクションをすべて単一のコマンドで処理するためです。
ps | awk '/11383/ {print $4}'
これは、11383
を含む行の4番目の列を印刷します。これを11383
に一致させたい場合、行の先頭に表示されている場合、ps | awk '/^11383/ {print $4}'
と言うことができます。
Bashのset
は、すべての出力を位置パラメーターに解析します。
たとえば、set $(free -h)
コマンドでは、echo $7
に「Mem:」と表示されます。
これらのすべての作業を行う代わりに、出力形式を変更するps機能を使用することをお勧めします。
ps -o cmd= -p 12345
プロセスのcmmand行を取得するには、pidを指定し、他には何も指定しません。
これはPOSIXに準拠しているため、移植性があると考えられます。