web-dev-qa-db-ja.com

awk printステートメントをチェーンする方法は?

さて、ここに簡単な例があります。ホストのIPV4を3つのステップで分離します。

ip -br a  
lo               UNKNOWN        127.0.0.1/8 ::1/128 
eth0             DOWN           
wlan0            UP             192.168.0.101/24 fe80::9fcd:45fb:1e0f:a1cc/64 
ip -br a | awk '/wlan0/ {print $3}'  
192.168.0.101/24
ip -br a | awk '/wlan0/ {print $3}' | awk -F '/' '{print $1}'
192.168.0.101

awkの2番目のインスタンスを呼び出す代わりに(1つの出力を次のインスタンスにパイプする)。どうすれば一度にすべてを行うことができますか?


言いたかったのですが、問題はipの出力を解析することではありません。質問を説明するのに役立つ簡単な例が必要でした。これが私が最初に思いついたものでした。本当の質問はタイトルに要約されています。

とにかく、それが何の価値があるかについて(私はそれをチェックする必要がありますが、私はかなり確信しています);これは私が(最近の)過去にしたことです:

ip -br a s dev wlan0 | awk -F '[ /]*' '{print $3}'
192.168.0.101
5
voices

他の回答は根本的な問題を解決しますが、「awk printステートメントをチェーンするにはどうすればよいですか?」という質問には実際には回答しません。

この種の問題に対する答えは、「あなたはしません」です。残りの言語を使用して、目的の結果が得られるまでソースを操作します。これは、他の2つの回答が行うことです。最終結果を出力するには、printのみを使用します。

_/wlan0/_(または私のWiFiの名前が異なるため、私の場合は_/^wl/_)などの初期範囲パターンを指定すると、アクションである_{}_内のコードのみが機能します。その文字列を含む入力行。

それができたら、その入力行で必要なことは何でもできます。

_ip -br a | \
awk '
/^wl/ {
  ip1 = $3
  gsub(/\/.*/, "", ip1)
  print ip1
}
'
_

このコードは、目的のフィールドを取得して変数に入れ、その変数の内容を編集してから出力します。

他の答えはこれと同じことをより効率的に行いますが、これは他のステップを追加できるより一般的なケースを示しています。結果を保存して、後で別の入力行などで見つかったもので使用することもできます。

実際には「印刷チェーン」のように見えるかもしれない何かのために、awkにはsprintf()関数があり、それはさらに処理するために変数への入力のフォーマットされた印刷を行うことができます。

または、1行に複数のものを出力する場合、コードは最後の1行まで改行なしで複数のprintf()ステートメントを使用して、出力行を1つずつ作成できます。

2
Joe

gsub を次のように使用できます。

ip -br a | awk '/wlan0/ {gsub(/\/.*/, ""); print $3}'
2
Stephen Rauch

フィールド区切り文字の定義を変更して、スペースと/の両方を含めるだけです。

$ ip -br a | awk -F'[[:blank:]/]+' '/wlan0/{print $3}'
192.168.0.101

オプション-F'[[:blank:]/]+'は、入力のフィールド区切り文字としてブランク、タブ、またはスラッシュの任意の組み合わせを使用するようにawkに指示します。

2
John1024

この場合、これを行う最も簡単な方法は、おそらく正規表現を使用して複数の区切り文字を設定することです。

ip -br a | awk -F '[\t /]*' '/wlan0/ {print$3}'

これにより、フィールド区切り文字が/、スペース、またはタブの任意の文字列になり、3番目のフィールドが出力されます。

arbitrary 2つのコマンドを実行するには、完全なawkプログラミング言語を学ぶ必要があります。私はそれに対してお勧めします-あなたはあなたの時間ともっと良いことをしていると確信しています。

2
Chris

これは、 Stephen Rauchの答え および Joeの答え の精神に多少似ていますが、より良いです:

awk '/wlan0/ {split($3, a, "/"); print a[1]}'

これは、3番目のフィールド($3)とsplitsを取り、/を区切り文字として使用します。コンポーネントは配列aに入り、サブフィールドの数が返されます。 (このスニペットでは、戻り値を無視しています。)したがって、a[1]は、3番目のフィールドの最初の/で区切られたサブフィールドです。

これは、他の回答よりも簡単に一般化できます。たとえば、入力が

真夜中の悲惨な時期に、私が熟考している間、弱くて疲れていました。
多くの古風で奇妙な量の忘れられた伝承— 
wlan0 foo/bar the/quick/brown/fox/jumps/over/the lazy/dog
うなずいて、ほとんど昼寝をしていると、突然タッピングが起こりました。
誰かが優しくラップしているとき、私の部屋のドアをラップしています。

次にコマンド

awk '/wlan0/ {if (split($3, a, "/") < 4) print "There is no fourth subfield";
                                    else print "The fourth subfield is", a[4]}'

foxからの戻り値をチェックして(少なくとも)4つのサブフィールドがあることを確認した後、3行目の3番目のフィールド(split)の4番目のサブフィールドを出力します。つまり、これは次のようなものです

awk '/wlan0/ {print $3}' | awk -F '/' '{print $4}'

単一のawkコマンドで、エラーチェックを行います。