質問
これを行いたい:
- コマンドを実行
- 出力をキャプチャする
- 行を選択
- その行の列を選択
例として、 $ 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番目の列の間にスペースを追加してテーブルの類似性を保つことです< code> 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
コマンドにはきちんとしたものがあるため、実際には簡潔にシェル関数を使用することも可能です。
$ <command> | while read a b; do echo $a; done
読み取る最初のパラメーター a
は最初の列を選択し、さらにある場合はその他すべてが 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が出力されます
正しい行(行番号6の例)の取得は頭と尾で行われ、正しい単語(単語番号4)はawkでキャプチャできます:
command|head -n 6|tail -n 1|awk '{print $4}'
配列変数の使用
set $(ps | egrep "^11383 "); echo $4
または
A=( $(ps | egrep "^11383 ") ) ; echo ${A[3]}
これらのすべての作業を行う代わりに、出力形式を変更するps機能を使用することをお勧めします。
ps -o cmd= -p 12345
pidが指定され、それ以外のプロセスのcmmand行を取得します。
これはPOSIXに準拠しているため、移植性があると見なされる可能性があります。
あなたのコマンド
ps | egrep 11383 | cut -d" " -f 4
回答で説明されているように、 tr -s
を使用してスペースを絞り込みます。
ただし、1つのコマンドでこれらのすべてのアクションを処理するため、 awk
を使用することもできます。
ps | awk '/11383/ {print $4}'
11383
を含む行の4番目の列を印刷します。これが 11383
と一致するようにしたい場合は、行の先頭に表示される場合、 ps | awk '/ ^ 11383 / {print $ 4}'
。
Bashの set
は、すべての出力を位置パラメーターに解析します。
たとえば、 set $(free -h)
コマンドでは、 echo $ 7
は&quot; Mem:&quot;