次のような単純なgrepを想定しています。
$ psa aux | grep someApp
1000 11634 51.2 0.1 32824 9112 pts/1 SN+ 13:24 7:49 someApp
これは多くの情報を提供しますが、psコマンドの最初の行がないため、情報のコンテキストはありません。 psの最初の行も表示することをお勧めします。
$ psa aux | someMagic someApp
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
1000 11634 51.2 0.1 32824 9112 pts/1 SN+ 13:24 7:49 someApp
もちろん、ps専用の正規表現をgrepに追加することもできます。
$ ps aux | grep -E "COMMAND|someApp"
ただし、他にも最初の行を追加したい場合があるため、より一般的な解決策を選択します。
これは "stdmeta"ファイル記述子 の良いユースケースと思われます。
通常、これをgrepで行うことはできませんが、他のツールを使用できます。 AWKについてはすでに触れましたが、次のようにsed
を使用することもできます。
sed -e '1p' -e '/youpattern/!d'
Sedユーティリティは、各行で個別に動作し、それらのそれぞれで指定されたコマンドを実行します。複数の-e
オプションを指定して、複数のコマンドを使用できます。各コマンドの前に、このコマンドを特定の行に適用する必要があるかどうかを指定する範囲パラメーターを付けることができます。
「1p」は最初のコマンドです。通常はすべての行を出力するp
コマンドを使用します。ただし、適用する範囲を指定する数値を付加します。ここでは、最初の行を意味する1
を使用します。さらに多くの行を印刷する場合は、x,yp
を使用できます。ここで、x
は印刷する最初の行、y
は印刷する最後の行です。たとえば、最初の3行を印刷するには、1,3p
を使用します
次のコマンドはd
で、通常はすべての行をバッファーから削除します。このコマンドの前に、2つの/
文字の間にyourpattern
を入れます。これは、コマンドを実行する必要がある行をアドレス指定するもう1つの方法です(最初は、p
コマンドで行ったように、どの行を指定するか)。つまり、このコマンドはyourpattern
に一致する行に対してのみ機能します。例外として、ロジックを反転するd
コマンドの前に!
文字を使用しています。したがって、指定したパターンに一致するしないのすべての行が削除されます。
最後に、sedはバッファに残っているすべての行を出力します。ただし、一致しない行はバッファから削除したため、一致する行のみが印刷されます。
要約すると、最初の行を出力してから、パターンに一致しないすべての行を入力から削除します。残りの行が出力されます(つまり、doがパターンに一致する行のみ)。
コメントで述べたように、このアプローチには問題があります。指定したパターンが最初の行にも一致する場合、2回出力されます(p
コマンドで1回、一致したため1回)。これは次の2つの方法で回避できます。
1d
の後に1p
コマンドを追加します。すでに述べたように、d
コマンドはバッファーから行を削除し、その範囲を番号1で指定します。つまり、最初の行のみを削除します。したがって、コマンドはsed -e '1p' -e '1d' -e '/youpattern/!d'
になります
1b
の代わりに1p
コマンドを使用します。それはトリックです。 b
コマンドを使用すると、ラベルで指定された他のコマンドにジャンプできます(この方法では、一部のコマンドを省略できます)。ただし、このラベルが指定されていない場合(この例のように)、コマンドの最後にジャンプするだけで、行の残りのコマンドは無視されます。したがって、私たちの場合、最後のd
コマンドはこの行をバッファーから削除しません。
ps aux | sed -e '1b' -e '/syslog/!d'
一部のsed
実装では、複数の-e
オプションを使用する代わりに、セミコロンを使用してコマンドを区切ることで、入力を節約できます。したがって、移植性を気にしない場合、コマンドはps aux | sed '1b;/syslog/!d'
になります。少なくともGNU sed
およびbusybox
の実装で機能します。
ただし、これはgrepでこれを行うためのかなりクレイジーな方法です。これは間違いなく最適ではありません。これは学習目的でのみ投稿していますが、システムに他のツールがない場合などに使用できます。
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog'
まず、-n
オプションを使用して、各行の前に行番号を追加します。一致するすべての行を列挙したいとします.*
-空の行も含め、何でも。コメントで提案されているように、「^」も一致させることができます。結果は同じです。
次に、拡張正規表現を使用して、ORとして機能する\|
特殊文字を使用できるようにします。したがって、行が1:
(最初の行)で始まるか、パターン(この場合はsyslog
)を含むかを突き合わせます。
ここでの問題は、この醜い行番号を出力で取得していることです。これが問題である場合、次のようにcut
を使用して削除できます。
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog' | cut -d ':' -f2-
-d
オプションは区切り文字を指定し、-f
は印刷するフィールド(または列)を指定します。したがって、すべての:
文字の各行を切り取り、2番目以降の列のみを印刷する必要があります。これにより、区切り文字で最初の列が効果的に削除され、これがまさに必要なものです。
awk
の代わりにgrep
を使用することについてどう思いますか?
chopper:~> ps aux | awk 'NR == 1 || /syslogd/'
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
root 19 0.0 0.0 2518684 1160 ?? Ss 26Aug12 1:00.22 /usr/sbin/syslogd
mrb 574 0.0 0.0 2432852 696 s006 R+ 8:04am 0:00.00 awk NR == 1 || /syslogd/
NR == 1
:レコード数== 1;すなわち。最初の行||
:または:/syslogd/
:検索するパターンpgrep
も一見の価値がありますが、これはユーザー向けの出力ではなくスクリプト用です。ただし、grep
コマンド自体は出力に表示されません。
chopper:~> pgrep -l syslogd
19 syslogd
ps aux | { read line;echo "$line";grep someApp;}
編集:コメントの後
ps aux | { head -1;grep someApp;}
私もhead -1
はすべての入力を読み取りますが、テストした後も機能します。
{ head -1;grep ok;} <<END
this is a test
this line should be ok
not this one
END
出力は
this is a test
this line should be ok
PSは内部フィルターをサポートし、
Bashプロセスを探しているとします。
ps -C bash -f
bash
という名前のすべてのプロセスをリストします。
stderrにヘッダーを送信する傾向があります:
ps | (IFS= read -r HEADER; echo "$HEADER" >&2; cat) | grep ps
これは通常、人間の読書目的には十分です。例えば。:
PID TTY TIME CMD
4738 pts/0 00:00:00 ps
括弧で囲まれた部分は、一般的な使用のために独自のスクリプトに入れることができます。
出力を(sort
などに)パイプすることができ、ヘッダーが上部に残るという便利な点もあります。
tee
およびhead
を使用することもできます。
ps aux | tee >(head -n1) | grep syslog
ただし、tee
がSIGPIPE
信号を無視できない限り(たとえば、 ここでの説明 を参照)、このアプローチを信頼できるようにするための回避策が必要です。回避策は、SIGPIPEシグナルを無視することです。これは、たとえば、シェルのようなbashで次のように実行できます。
trap '' PIPE # ignore SIGPIPE
ps aux | tee >(head -n1) 2> /dev/null | grep syslog
trap - PIPE # restore SIGPIPE handling
出力順序は保証されません にも注意してください。
おそらく2つのps
コマンドが最も簡単でしょう。
$ ps aux | head -1 && ps aux | grep someApp
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
100 3304 0.0 0.2 2466308 6476 ?? Ss 2Sep12 0:01.75 /usr/bin/someApp
Pidstatは以下で使用できます。
pidstat -C someApp
or
pidstat -p <PID>
例:
# pidstat -C Java
Linux 3.0.26-0.7-default (hostname) 09/12/12 _x86_64_
13:41:21 PID %usr %system %guest %CPU CPU Command
13:41:21 3671 0.07 0.02 0.00 0.09 1 Java
テストのために、以下を.bashrcファイルに挿入するか、最初にシェルにコピーして貼り付けます。
function psls {
ps aux|head -1 && ps aux|grep "$1"|grep -v grep;
}
使用法:psls [grep pattern]
$ psls someApp
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
root 21 0.0 0.0 2467312 1116 ?? Ss Tue07PM 0:00.17 /sbin/someApp
必ず.bashrc(または、代わりに.bash_profileを配置する場合は.bash_profile)を入手してください。
source ~/.bashrc
この関数は、シェルコマンドラインでもオートコンプリートします。別の答えで述べたように、最初の行をファイルにパイプして、psへの1つの呼び出しを保存できます。
# print the header (the first line of input)
# and then run the specified command on the body (the rest of the input)
# use it in a pipeline, e.g. ps | body grep somepattern
body() {
IFS= read -r header
printf '%s\n' "$header"
"$@"
}
そして、このように使います
$ ps aux | body grep someApp
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
1000 11634 51.2 0.1 32824 9112 pts/1 SN+ 13:24 7:49 someApp
Comp.unix.ShellのJanis Papanagnouに感謝します。次の関数を使用します。
function grep1 {
IFS= read -r header && printf "%s\n" "$header"; grep "$@"
}
これには多くの利点があります。
-i
大文字と小文字を区別しないマッチングの場合、-E
拡張正規表現など.使用例:
$ ps -rcA | grep1 databases
PID TTY TIME CMD
$ ps -rcA | grep1 -i databases
PID TTY TIME CMD
62891 ?? 0:00.33 com.Apple.WebKit.Databases
Perlの方法:
ps aux | Perl -ne 'print if /pattern/ || $.==1'
sed
よりも読みやすく、高速で、不要な行を選択するリスクがありません。
それが完全なヘッダーを持つgreppingプロセスのみの場合は、@ mrbの提案を拡張します。
$ ps -f -p $(pgrep bash)
UID PID PPID C STIME TTY STAT TIME CMD
nasha 2810 2771 0 2014 pts/6 Ss+ 0:00 bash
...
pgrep bash | xargs ps -fp
でも同じ結果が得られますが、サブシェルはありません。他のフォーマットが必要な場合:
$ pgrep bash | xargs ps fo uid,pid,stime,cmd -p
UID PID STIME CMD
0 3599 2014 -bash
1000 3286 2014 /bin/bash
...