2行に表示されるテキストに対してgrepをどのように実行しますか?
例えば:
pbsnodes
は、Linuxクラスターの使用率を返すコマンドです。
root$ pbsnodes
node1
state = free
procs = 2
bar = foobar
node2
state = free
procs = 4
bar = foobar
node3
state = busy
procs = 8
bar = foobar
「フリー」状態のノードに一致するプロシージャの数を確認したい。これまでのところ、「プロシージャの数」と「フリー状態のノード」を特定することができましたが、それらをすべてのフリープロシージャを表示する1つのコマンドに結合したいと考えています。
上記の例では、正解は6(2 + 4)になります。
私が持っているもの
root$ NUMBEROFNODES=`pbsnodes|grep 'state = free'|wc -l`
root$ echo $NUMBEROFNODES
2
root$ NUMBEROFPROCS=`pbsnodes |grep "procs = "|awk '{ print $3 }' | awk '{ sum+=$1 } END { print sum }'`
root$ echo $NUMBEROFPROCS
14
'procs = x'と表示されているすべての行を検索するにはどうすればよいですか。ただし、その上の行が 'state = free'と表示されている場合のみですか?
データが常にその形式である場合は、単純にそれを書き込むことができます。
awk -vRS= '$4 == "free" {n+=$7}; END {print n}'
(RS=
はレコードが段落であることを意味します)。
または:
awk -vRS= '/state *= *free/ && match($0, "procs *=") {
n += substr($0,RSTART+RLENGTH)}; END {print n}'
$ pbsnodes
node1
state = free
procs = 2
bar = foobar
node2
state = free
procs = 4
bar = foobar
node3
state = busy
procs = 8
bar = foobar
$ pbsnodes | grep -A 1 free
state = free
procs = 2
--
state = free
procs = 4
$ pbsnodes | grep -A 1 free | grep procs | awk '{print $3}'
2
4
$ pbsnodes | grep -A 1 free | grep procs | awk '{print $3}' | paste -sd+
2+4
$ pbsnodes | grep -A 1 free | grep procs | awk '{print $3}' | paste -sd+ | bc
6
pcregrep
を使用してこれを行う1つの方法を次に示します。
$ pbsnodes | pcregrep -Mo 'state = free\n\s*procs = \K\d+'
2
4
$ pbsnodes | \
pcregrep -Mo 'state = free\n\s*procs = \K\d+' | \
awk '{ sum+=$1 }; END { print sum }'
6
GNU grep
の実装には、一致の前(-B
)と後(-A
)の行も出力する2つの引数が付属しています。スニペットmanページ:
-A NUM, --after-context=NUM
Print NUM lines of trailing context after matching lines. Places a line containing a group separator (--) between contiguous groups of matches. With the -o or
--only-matching option, this has no effect and a warning is given.
-B NUM, --before-context=NUM
Print NUM lines of leading context before matching lines. Places a line containing a group separator (--) between contiguous groups of matches. With the -o or
--only-matching option, this has no effect and a warning is given.
したがって、あなたの場合、state = free
をgrepし、次の行も出力する必要があります。それを質問のスニペットと組み合わせると、次のようなものが得られます。
usr@srv % pbsnodes | grep -A 1 'state = free' | grep "procs = " | awk '{ print $3 }' | awk '{ sum+=$1 } END { print sum }'
6
そして少し短い:
usr@srv % pbsnodes | grep -A 1 'state = free' | awk '{ sum+=$3 } END { print sum }'
6
固定長データ(レコード内の行数を参照する固定長)がある場合は、sed
でN
コマンドを(数回)使用して、次の行を結合できます。パターンスペース:
sed -n '/^node/{N;N;N;s/\n */;/g;p;}'
次のような出力が得られるはずです:
node1;state = free;procs = 2;bar = foobar
node2;state = free;procs = 4;bar = foobar
node3;state = busy;procs = 8;bar = foobar
可変レコード構成(たとえば、空の区切り線を使用)では、分岐コマンドt
およびb
を使用できますが、awk
を使用すると、快適な方法。
...そして、これがPerlソリューションです:
pbsnodes | Perl -lne 'if (/^\S+/) { $node = $& } elsif ( /state = free/ ) { print $node }'
awk
getline
コマンドを使用できます:
$ pbsnodes | awk 'BEGIN { freeprocs = 0 } \
$1=="state" && $3=="free" { getline; freeprocs+=$3 } \
END { print freeprocs }'
man awk
から:
getline Set $0 from next input record; set NF, NR, FNR.
getline <file Set $0 from next record of file; set NF.
getline var Set var from next input record; set NR, FNR.
getline var <file Set var from next record of file.
command | getline [var]
Run command piping the output either into $0 or var, as above.
command |& getline [var]
Run command as a co-process piping the output either into $0 or var, as above. Co-processes are a
gawk extension.