
次の例では、各デバイスに接続されているアドレスの数を計算したいと思います。 awkまたはsedを使用する方が良いです。
/dev/1
addr1 sometext sometext sometext
addr2 sometext sometext sometext
addr3 sometext sometext sometext
/dev/2
wwpn1 sometext sometext sometext
wwpn2 sometext sometext sometext
/dev/3
addr1 sometext sometext sometext
addr2 sometext sometext sometext
addr3 sometext sometext sometext
addr4 sometext sometext sometext
/dev/4
addr1 sometext sometext sometext
以下は一致を提供しますが、手動でコマンドを複数回実行する以外は、すべてのデバイスに対してこれを増やすことはできません。
sed -n '/\/dev\/1/,/\/dev\/2/'p
/dev/1
addr1 sometext sometext sometext
addr2 sometext sometext sometext
addr3 sometext sometext sometext
/dev/2
私が望むのは、すべてのデバイスを繰り返すことです。次のようになります。
for i in `grep 'dev' somefile`; do sed -n '/$i/,/$insersecondmatchhere/'p ; done
問題は、コマンドの先頭にあるforループから$ insertsecondmatchhere変数を取得する方法がわからないことです。
答え1
これは簡単なアプローチですawk
。 /dev/[0-9] モードがある場合は、既存に保存されたモードとカウントをダンプし、デバイスとカウントをリセットし、そうでなければカウンタをインクリメントします。 EOFに達すると、保存されたモードとカウントをダンプします。
#!/bin/awk -f
{
if ( /\/dev\/[0-9]/ ) {
if (dev) { print dev, count; };
dev=$0;
count=0;
} else {
++count;
}
}
END {
print dev, count;
}
いくつかのawkバージョンとterdonのperlソリューションがあるので、これは初期の方向のように見えるので、見苦しいbash + grep + sedソリューションです。
#!/usr/bin/env bash
declare -a devs
devs=( $(grep ^/dev/ input) )
for ((i=0; i < ${#devs[@]} - 1; i++)); do
start=${devs[i]}
end=${devs[i+1]}
start=${start//\//\\\/}
end=${end//\//\\\/}
count=$(sed -n "/^$start/,/^$end/p" input | wc -l)
count=$(( count - 2 ))
echo for ${devs[i]}, count is $count
done
start=${devs[i]}
start=${start//\//\\\/}
count=$(sed -n "/^$start/,\$p" input | wc -l)
count=$(( count - 1 ))
echo for ${devs[i]}, count is $count
主なトリックは、デバイス名をsed
。
答え2
このような?
awk -v RS="/dev/" 'NR!=1 {print "/dev/"$1":"NF-1}' file.txt
答え3
別のawk
方法:
$ awk '{if(/^\//){n=$0;}else{l[n]++}}END{for(n in l){print n" : "l[n]}}' file
/dev/1 : 3
/dev/2 : 2
/dev/3 : 4
/dev/4 : 1
n
現在の行がで終わると、それ以外の場合は連想配列に格納されている現在の値だけ/
増加します。これにより、各セクションの行数が計算されます。ファイル全体を読み取ったら、チャンクでそれぞれ(セクション名、行数)とそのセクションの行数を印刷します。l[n]
l
n
END{}
n
dev
ゴルフをすることができます:
awk '{/^\//?n=$0:l[n]++;}END{for(n in l){print n" : "l[n]}}' file
(golf)Perlでも同じアイデアが適用されます。
$ perl -lne'/^\//?$n=$_:$l{$n}++;}{print"$_ : $l{$_}"for keys(%l)' file
/dev/2 : 2
/dev/1 : 3
/dev/3 : 4
/dev/4 : 1
次に拡張可能:
perl -lne 'if(/^\//){$n=$_}
else{ $l{$n}++ }
END{print"$_ : $l{$_}" for keys(%l)}' file