文字列sが与えられると
s="B /home/BL/004_010_0100.0 23 0.031"
文字列内のパス、タブ、スペースの後の数字だけを把握する方法は?
上記の文字列sから数字23を抽出したいと思います。
num=$(echo $s | grep 'B .*\t (\d*)')
答え1
文字列をスペースで区切られたフィールドのセットとして扱います。最後から2番目のフィールドが必要です。
num=$( awk '{ print $(NF-1) }' <<<"$s" )
またはここに文字列がないシェルでは、
num=$( printf '%s\n' "$s" | awk '{ print $(NF-1) }' )
これにより、コマンド$s
に文字列が入力されます。awk
このawk
コマンドは、スペースで区切られた最後のフィールドから2番目のフィールドを出力します。結果はnum
変数に割り当てられます。
テスト:
$ s="B /home/BL/004_010_0100.0 23 0.031"
$ num=$( awk '{ print $(NF-1) }' <<<"$s" )
$ printf 'num is "%s"\n' "$num"
num is "23"
データが$s
コマンドから出た場合は、awk
中間変数に保存する代わりに直接入力できます。
num=$( some-command | awk '{ print $(NF-1) }' )
grep
一致するアイテムを返すツールです。ワイヤー-o
(このツールの一部の実装で利用可能な非標準オプションは無視してください。)最初に、文字列の空白に基づいて文字列を複数行に変換すると、それを使用してgrep
数値を選択できます。$s
$ tr -s '[:blank:]' '[\n*]' <<<"$s" | grep -x '[[:digit:]]\{1,\}'
23
ここで使用されるコマンドは、tr
文字列を次から変換します。
B /home/BL/004_010_0100.0 23 0.031
入力する
B
/home/BL/004_010_0100.0
23
0.031
grep
コマンドがこの行を選択しました。ただ数値で構成されます(この-x
オプションは、指定されたパターンが完全な行に一致するように強制します)。明らかに、これは探している数が正の整数である場合にのみ機能します。
2番目の「フィールド」に興味があることがわかっている場合は、代わりに次のものを使用できtail
ますhead
。
$ tr -s '[:blank:]' '[\n*]' <<<"$s" | tail -n 2 | head -n 1
23
...またはsed
:
$ tr -s '[:blank:]' '[\n*]' <<<"$s" | sed -n -e '${ g; p; }' -e h
23
上記のすべてのバリエーションは標準であり、移植可能です。非標準ユーティリティを使用して行を 2 回反転するcut
と、最後から 2 番目のフィールドを抽出するためにも使用できます。rev
$ rev <<<"$s" | tr -s '[:blank:]' '[\t*]' | cut -f 2 | rev
23
ここでは、tr
すべての空白文字を置き換えるためにタブを使用します(次のように圧縮します)。一つタブ)。 cut
次に、2番目のフィールドを抽出し、rev
抽出されたデータを再度反転します。
答え2
Perlでこれを試すことができます:
echo "$s" | perl -e 'for(<>){/B\s+.*?\s+(\d+)\s+/;print $1}'
ここでは、次のような文字列を探します。
B
特徴- その後に1つ以上の空白文字が続きます。
\s+
- 最初の空白文字の前にすべての怠惰な文字が続きます。
.*?\s+
- 以下は私たちが望む数字です。括弧内のキャプチャグループにキャプチャして特殊変数
(\d+)
に保存します。$1
- その後には1つ以上の空白文字が続きます
\s+
。
この正規表現は改善することができます(たとえば、^
演算子$
を使用して文字列の始まりと終わりを示す)。
もっと読む正規表現について。
答え3
GNU grep
(Linux システムの既定値) にアクセスできる場合、この正規表現は小数点以下の桁なしで数値をキャプチャします。
grep -oP '\b(?<!\.)\d+(?!\.)\b'
正規表現の説明:
\b
単語境界マッチ(?<!\.)
.
Negative Lookbehindは、()の後に小数点がないと主張します。\d+
数字が複数回一致します。(?!\.)
Negative Lookaheadは前に小数点がないと主張します(.
)。\b
単語境界マッチ
答え4
grep
少し変わっただけです。 GNU grep
(Linuxシステムのデフォルト)を使用している場合は、次のように動作します。
s="B /home/BL/004_010_0100.0 23 0.031"
num=$(echo $s | grep -oP '\.*?\s+\d+\s+')