sedは、その行の最初のパターン一致のみを印刷します。

sedは、その行の最初のパターン一致のみを印刷します。

私は次のデータを持っています。

<td><a href="data1">abc</a> ... <a href="data2">abc</a> ... <a href="data3">abc</a>

data(上記の行は以下のコードのように参照されます)

data1最初の間に必要なので、"これを"行います。

echo 'data' | sed 's/.*"\(.*\)".*/\1/'

しかし、それは私に返されます最後の文字列"と常につまり、この場合の代わりに"私を返します。data3data1

を得るために、data1私は結局

echo 'data' | sed 's/.*"\(.*\)".*".*".*".*".*/\1/'

data1そう多くの重複なしにこれをどのように得ることができますか?sed

答え1

正規.*表現パターンは貪欲であり、可能な限り長い文字列と一致するため、一致する引用符が最後の引用符になります。

ここで区切り文字は単一の文字であるため、逆括弧セットを使用して引用符(たとえば)を除くすべての項目と一致させ、その一致を繰り返すことで引用符ではなく複数の[^"]文字と一致させることができます。

$ echo '... "foo" ... "bar" ...' | sed 's/[^"]*"\([^"]*\)".*/\1/'
foo

もう1つの方法は、最初の参照より前のすべての項目を削除してから、(新しい)最初の参照から始まるすべての項目を削除することです。

$ echo '... "foo" ... "bar" ...' | sed 's/^[^"]*"//; s/".*$//'
foo

Perl正規表現では、疑問符を追加して指定子を貪欲にしないようにすることができ、*できるだけ少ない文字/バイトのみを除くと何でも可能です。+.*?

答え2

HTMLを解析するために単純な正規表現を使用することに関する古典的な警告であなたを退屈させません。私が言いたいのは、専用パーサーを使用する必要があるということです。つまり、ここでの問題は、sed貪欲なマッチを使用することです。したがって、常に最長の文字列と一致します。これはあなたが.*永遠に持続し、ライン全体と一致することを意味します。

(以下を参照)でこれを行うことができますが、sed貪欲ではない一致を可能にするツールを使用する方が簡単です。

$ perl -pe 's/.*?"(.*?)".*/$1/' file
data1

non-greedyマッチングをサポートしていないため、sed追加のトリックが必要です。最も簡単な方法は、「引用符なし」方法を使用することです。イカチュウの答え。代替案は次のとおりです。

$ rev file | sed 's/.*"\(.*\)".*/\1/' | rev
data1

これは元の方法を使用してファイル(rev)を元に戻しました。これで、最初の項目が最後の項目であるために機能し、ファイルを再び戻します。

答え3

さまざまな方法で入力からdata1を抽出できます。

grep -oP '^[^"]*"\K[^"]*'

sed -ne '
   /\n/!{y/"/\n/;D;}
   P
'

perl -lne '/"([^"]*)"/ and print($1),last'

答え4

Perl正規表現の予測と予測を使用して、貪欲な検索を使用することもできます。

cat data | grep -Po '(?<=href=").*?(?=")' | head -n1

関連情報