キャプチャしたグループのみを出力するようにsed
に指示する方法はありますか?例えば次のような入力があります。
This is a sample 123 text and some 987 numbers
そしてパターン:
/([\d]+)/
後方参照によってフォーマットされた方法で123と987の出力だけを取得できますか?
これを機能させる鍵は、sed
に、出力したくないものを除外するように指示することと、必要なものを指定することです。
string='This is a sample 123 text and some 987 numbers'
echo "$string" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
これは言う:
-n
)p
)一般的に、sed
では括弧を使ってグループをキャプチャし、後方参照を使ってキャプチャしたものを出力します。
echo "foobarbaz" | sed 's/^foo\(.*\)baz$/\1/'
"bar"を出力します。拡張正規表現に-r
(OS Xの場合は-E
)を使用する場合は、括弧をエスケープする必要はありません。
echo "foobarbaz" | sed -r 's/^foo(.*)baz$/\1/'
最大9つのキャプチャグループとそれらの後方参照があります。後方参照はグループの出現順に番号が付けられていますが、それらは任意の順序で使用でき、繰り返し使用できます。
echo "foobarbaz" | sed -r 's/^foo(.*)b(.)z$/\2 \1 \2/'
"a bar a"を出力します。
GNU grep
がある場合(OS Xを含むBSDでも動作するかもしれません):
echo "$string" | grep -Po '\d+'
または次のような変形
echo "$string" | grep -Po '(?<=\D )(\d+)'
-P
オプションはPerl互換の正規表現を有効にします。 man 3 pcrepattern
または man 3 pcresyntax
を参照してください。
Sedには最大9つの記憶されたパターンがありますが、正規表現の一部を覚えるにはエスケープした括弧を使用する必要があります。
例と詳細については、 こちら を参照してください。
grepが使えます
grep -Eow "[0-9]+" file
私は質問で与えられたパターンはほんの一例にすぎず、目標はanyに一致することであったと思います。 - )パターン。
パターンスペースに改行を挿入できるようにGNU拡張子を持つsedがある場合、1つの提案があります:
> set string = "This is a sample 123 text and some 987 numbers"
>
> set pattern = "[0-9][0-9]*"
> echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p"
123
987
> set pattern = "[a-z][a-z]*"
> echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p"
his
is
a
sample
text
and
some
numbers
これらの例は、CYGWINを使用したtcsh(はい、Iが知っているのシェル)です。 (編集:bashの場合は、setと=の前後のスペースを削除します。)
Perlをあきらめて使ってください
sed
はそれをカットしないので、タオルを投げてPerlを使いましょう。少なくともgrep
GNUの間は LSB 拡張子はありません:-)
一致する部分全体を印刷します。一致するグループはありません。
cat <<EOS | Perl -lane 'print m/\d+/g'
a1 b2
a34 b56
EOS
出力:
12
3456
1行に1回の一致、多くの場合構造化データフィールド
cat <<EOS | Perl -lape 's/.*?a(\d+).*/$1/g'
a1 b2
a34 b56
EOS
出力:
1
34
後ろから見て
cat <<EOS | Perl -lane 'print m/(?<=a)(\d+)/'
a1 b2
a34 b56
EOS
複数のフィールド
cat <<EOS | Perl -lape 's/.*?a(\d+).*?b(\d+).*/$1 $2/g'
a1 c0 b2 c0
a34 c0 b56 c0
EOS
出力:
1 2
34 56
1行に複数の一致、多くの場合非構造化データ
cat <<EOS | Perl -lape 's/.*?a(\d+)|.*/$1 /g'
a1 b2
a34 b56 a78 b90
EOS
出力:
1
34 78
後ろから見て
cat EOS<< | Perl -lane 'print m/(?<=a)(\d+)/g'
a1 b2
a34 b56 a78 b90
EOS
出力:
1
3478
この回答は、任意の数の数字グループで機能します。例:
$ echo 'Num123that456are7899900contained0018166intext' |
> sed -En 's/[^0-9]*([0-9]{1,})[^0-9]*/\1 /gp'
123 456 7899900 0018166
キャプチャしたグループのみを出力するようにsedに指示する方法はありますか?
はい。すべてのテキストをキャプチャグループに置き換えます。
$ echo 'Number 123 inside text' | sed 's/[^0-9]*\([0-9]\{1,\}\)[^0-9]*/\1/'
123
s/[^0-9]* # several non-digits
\([0-9]\{1,\}\) # followed by one or more digits
[^0-9]* # and followed by more non-digits.
/\1/ # gets replaced only by the digits.
あるいは拡張された構文(より少ないバッククォートと+の使用を可能にします):
$ echo 'Number 123 in text' | sed -E 's/[^0-9]*([0-9]+)[^0-9]*/\1/'
123
番号がないときに元のテキストを印刷しないようにするには、次のようにします。
$ echo 'Number xxx in text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1/p'
そして、いくつかの数字を一致させる(そしてそれらを印刷する):
$ echo 'N 123 in 456 text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1 /gp'
123 456
これは、任意の桁数に対して有効です。
$ str='Test Num(s) 123 456 7899900 contained as0018166df in text'
$ echo "$str" | sed -En 's/[^0-9]*([0-9]{1,})[^0-9]*/\1 /gp'
123 456 7899900 0018166
これはgrepコマンドとよく似ています。
$ str='Test Num(s) 123 456 7899900 contained as0018166df in text'
$ echo "$str" | grep -Po '\d+'
123
456
7899900
0018166
とパターン:
/([\d]+)/
Sedは '\ d'(ショートカット)構文を認識しません。上記の[0-9]
で使用されているASCIIの同等物は正確には同等ではありません。唯一の代替解決策は文字クラスを使うことです: '[[:digit:]] `。
選択された答えは、そのような「文字クラス」を使って解決策を構築します。
$ str='This is a sample 123 text and some 987 numbers'
$ echo "$str" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
その解決策は、(正確に)2桁の数字に対してのみ機能します。
もちろん、答えはシェル内で実行されているので、そのような答えを短くするために2つの変数を定義することができます。
$ str='This is a sample 123 text and some 987 numbers'
$ d=[[:digit:]] D=[^[:digit:]]
$ echo "$str" | sed -rn "s/$D*($d+)$D+($d+)$D*/\1 \2/p"
しかし、すでに説明したように、s/…/…/gp
コマンドを使用するのがより良いです。
$ str='This is 75577 a sam33ple 123 text and some 987 numbers'
$ d=[[:digit:]] D=[^[:digit:]]
$ echo "$str" | sed -rn "s/$D*($d+)$D*/\1 /gp"
75577 33 123 987
それは繰り返し実行される数字と短い(er)コマンドを書くことの両方をカバーするでしょう。
やってみる
sed -n -e "/[0-9]/s/^[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*$/\1 \2 \3 \4 \5 \6 \7 \8 \9/p"
私はcygwinの下でこれを得ました:
$ (echo "asdf"; \
echo "1234"; \
echo "asdf1234adsf1234asdf"; \
echo "1m2m3m4m5m6m7m8m9m0m1m2m3m4m5m6m7m8m9") | \
sed -n -e "/[0-9]/s/^[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*$/\1 \2 \3 \4 \5 \6 \7 \8 \9/p"
1234
1234 1234
1 2 3 4 5 6 7 8 9
$
それはOPが要求したことではありません(グループのキャプチャ)が、あなたは数を使って数を抽出することができます:
S='This is a sample 123 text and some 987 numbers'
echo "$S" | sed 's/ /\n/g' | sed -r '/([0-9]+)/ !d'
以下を与えます:
123
987