単純なディスク使用シェルスクリプト(ダッシュ)を作成しようとしていますが、AWK構文に慣れていないため、文字列を解析する方法がわかりません。
私は次のコマンドを使用します。df -P -BG /
たとえば、次のような出力が表示されます。
Filesystem xxxxxxxxxx-blocks Used Available Capacity Mounted on
/dev/mapper/xxx_crypt 500G 200G 100G xx% /
「使用済み」(最終的には「使用可能」)の下の列を抽出したいのですが、どうすればよいかわかりません。 AWKには次の検索コマンドがあることがわかります。awk '/Used/ {print}'
しかし、その下の行を取得する方法がわかりません。どのようなヒントがありますか?たとえば、df -P -BG / | awk '...'
シェル変数に格納するので、1行でパイプとして機能することが重要ですが、複数行のAWKを使用できるため、必ずしも必要とは思いません。
答え1
実装がサポートしている場合は、構文解析の代わりにdf
使用できます。私のアーチLinux--output
から:man df
--output[=FIELD_LIST]
use the output format defined by FIELD_LIST, or print all fields if
FIELD_LIST is omitted.
[...]
FIELD_LIST is a comma-separated list of columns to be included.
Valid field names are: 'source', 'fstype', 'itotal', 'iused',
'iavail', 'ipcent', 'size', 'used', 'avail', 'pcent',
'file' and 'target' (see info page).
したがって、あなたの場合は、次のことを行います。
$ df -BG --output="used" /
Used
200G
本当に構文解析が必要な場合は、パターンマッチングにまったく気にしません。入力を制御しても変更されないため、3番目のフィールド(私のシステムの出力)のみを印刷できます。
$ df -P -BG / | awk '{print $3}'
Used
44G
フィールドの順序が変わっても機能する必要がある場合、文字列を含むフィールドを見つける必要がある場合は、Used
次のように複雑な操作を実行できます。
$ df -P -BG / |
awk '{ if(NR==1){for(i=1; i<=NF; i++){ if($i ~ /Used/){want=i}}} print $want}'
Used
44G
答え2
FPAT、FIELDIDTHS、\s、\S、および gensub() とともに GNU awk を使用します。
$ cat tst.awk
BEGIN { FPAT="\\S+|\\s+"; OFS="\t" }
NR == 1 {
sub(/Mounted on/,"Mounted_on")
for ( i=1; i<=NF; i+=2 ) {
tags[++numTags] = $i
wids = wids " " length($i $(i+1))
}
FIELDWIDTHS = wids
$0 = $0
}
{
for ( i=1; i<=NF; i++ ) {
f[tags[i]] = gensub(/^\s+|\s+$/,"","g",$i)
}
print f["Filesystem"], f["Available"], f["Used"]
}
$ cat file | awk -f tst.awk | column -s $'\t' -t
Filesystem Available Used
/dev/mapper/xxx_crypt 100G 200G
私にないものと交換してくださいcat file
。ソートのために列をdf -P -BG /
パイプで接続しましたが、column
これは必要ありません。
これにより、名前で印刷、比較、並べ替え、目的の列の値に対して算術演算を実行するなどの操作を実行できます。コードで修正しなければならなかった唯一のことは、スペースをアンダースコアに変更して「インストール」することでした。
以下は、すべてのawkで動作するバージョンです。
$ cat tst.awk
BEGIN { OFS="\t" }
NR == 1 {
sub(/Mounted on/,"Mounted_on")
while ( match(substr($0,totWid+1),/[^ \t]+[ \t]*/) ) {
tag = substr($0,totWid+1,RLENGTH)
sub(/[ \t]+$/,"",tag)
tags[++numTags] = tag
begs[numTags] = totWid + 1
wids[numTags] = RLENGTH
totWid += RLENGTH
}
}
{
for ( i=1; i<=numTags; i++ ) {
val = substr($0,begs[i],wids[i])
gsub(/^[ \t]+|[ \t]+$/,"",val)
f[tags[i]] = val
}
print f["Filesystem"], f["Available"], f["Used"]
}
$ awk -f tst.awk file | column -s $'\t' -t
Filesystem Available Used
/dev/mapper/xxx_crypt 100G 200G
答え3
使用幸せ(以前のPerl_6)
~$ raku -e 'my $target = "Used";
my @table = lines.map: *.split(/ \h+ /).List;
my $col = @table.head.grep(/ $target /, :k).cache;
.put for @table.map: *.[ $col.flat ];' file
上記は、Perlシリーズのプログラミング言語であるRakuで書かれた答えです。つまり、$
-sigiled スカラーが宣言され、「Used」という文字列が割り当てられます。その後、lines
読み取ると各ペッドが水平スペースmap
に入ります。通常、これらの戻りはRakuのaという軽量データ構造に格納されますが、ここではデータを配列に格納することを強制します。split
\h
Seq
List
@table
それでは正しい列を見てください。@table.head
テーブルの元のヘッダー行(つまり行)を取得します。grep
一致を見つけるためにこれらの要素を調べて、列$target
インデックス:k
番号のキーを取得して保存します$col
。最後に、必要な列のみを返してput
データを出力します。@a.table
$col
入力例:
Filesystem xxxxxxxxxx-blocks Used Available Capacity Mounted on
/dev/mapper/xxx_crypt 500G 200G 100G xx% /
出力例:
Used
200G
OPは、シェル変数を受け入れるスクリプトの希望を表現しました。 Rakuには、%*ENV
シェル変数にアクセスするために使用できる特別な関連配列があります。したがって、次はcolName
環境(つまりシェル)からシェル変数を取得します。
~$ env colName="Used" raku -e 'my $target = %*ENV<colName>; \
my @table = lines.map: *.split(/ \h+ /).List; \
my $col = @table.head.grep(/$target/, :k).cache; \
.put for @table.map: *.[ $col.flat ];' file
Used
200G
次のように、わずかな調整で同様に2つの列などを返すことができます。
~$ env colNames="Used Available" raku -e ' \
my @target = %*ENV<colNames>.split(/ \h+ /).List; \
my @table = lines.map: *.split(/ \h+ /).List; \
my @col = @table.head.grep(/@target/, :k); \
.put for @table.map: *.[ @col.flat ];' file
Used Available
200G 100G