回答:
これを機能させるための鍵は、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/'
「バー」を出力します。拡張正規表現に-r
(-E
OS Xの場合)を使用する場合、括弧をエスケープする必要はありません。
echo "foobarbaz" | sed -r 's/^foo(.*)baz$/\1/'
最大9つのキャプチャグループとその後方参照が存在できます。後方参照は、グループが表示される順序で番号が付けられていますが、任意の順序で使用でき、繰り返すことができます。
echo "foobarbaz" | sed -r 's/^foo(.*)b(.)z$/\2 \1 \2/'
「バー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
例を参照している場合、-r
オプション(または-E
OS Xの場合はIIRC)を使用する場合は、括弧をエスケープする必要はありません。違いは、基本正規表現と拡張正規表現(-r
)の違いです。
Sedには最大9つのパターンが記憶されていますが、正規表現の一部を記憶するにはエスケープされた括弧を使用する必要があります。
例と詳細については、こちらをご覧ください
sed -e 's/version=\(.+\)/\1/' input.txt
これでもinput.txt全体が出力されます
\+
代わりに書く必要があり+
ます。また、なぜ-e
sedコマンドを1つだけ使用するのか理解できません。
sed -e -n 's/version=\(.+\)/\1/p' input.txt
以下を参照してください。mikeplate.com/2012/05/09/...
sed -E
Perl / Java / JavaScript / Go /その他のフレーバーに非常によく似た、いわゆる「モダン」または「拡張」正規表現を使用することをお勧めします。(と比較grep -E
またはegrep
。)デフォルトの構文は、これらの奇妙なエスケープのルールがあり、「時代遅れ」と考えられています。2つの違いの詳細については、を実行してくださいman 7 re_format
。
あなたはgrepを使うことができます
grep -Eow "[0-9]+" file
o
オプションがある理由です-unixhelp.ed.ac.uk/CGI/man-cgi?grep:-o、--only-matching PATTERNと一致する一致する行の部分のみを表示
grep -Eow -e "[0-9]+" -e "[abc]{2,3}"
ます。前のgrepからのパイプ処理を除いて、これらの2つの式を1行に配置するように要求する方法がわかりません(いずれかのパターンが1行で複数回一致する場合でも機能しません) )。
この回答は、任意の桁数のグループで機能します。例:
$ 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桁の数字に対してのみ機能します。
もちろん、答えはシェル内で実行されているため、このような答えを短くするためにいくつかの変数を定義できます。
$ 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
これは、数字の繰り返し実行と、short(er)コマンドの書き込みの両方をカバーします。
質問で与えられたパターンは単なる例であり、目標はどのパターンにも一致することでした。
パターンスペースに改行を挿入できる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(そう、私はその間違ったシェルを知っています)を使用しています。(編集:bashの場合、セットと=の前後のスペースを削除します。)
+
、それをエスケープするか、-r
オプション(-E
OS Xの場合)を使用する必要があります。また、使用することができます\{1,\}
(または-r
または-E
エスケープせず)。
Perlをあきらめて使用する
sed
はそれをカットしないので、タオルを投げてPerlを使用してみましょう。少なくともそれはLSBですが、grep
GNU拡張はそうではありません:-)
一致する部分全体を印刷します。一致するグループや後読みは必要ありません。
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
試す
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
$
sed
、-E
フラグを使用して拡張正規表現をオンにする必要があることに注意してください。