Yanıtlar:
Bunu işe almanın anahtarı, çıktı almak sed
istemediğiniz şeyi hariç tutmanın yanı sıra ne istediğinizi belirtmektir.
string='This is a sample 123 text and some 987 numbers'
echo "$string" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
Bu diyor ki:
-n
)p
)Genel olarak, sed
parantez kullanarak grupları yakalar ve geri referans kullanarak yakaladığınız şeyi çıkarırsınız:
echo "foobarbaz" | sed 's/^foo\(.*\)baz$/\1/'
"bar" çıktısı verecektir. Genişletilmiş regex için -r
( -E
OS X için) kullanıyorsanız , parantezlerden kaçmanız gerekmez:
echo "foobarbaz" | sed -r 's/^foo(.*)baz$/\1/'
9 adede kadar yakalama grubu ve bunların geri referansları olabilir. Arka referanslar, grupların göründüğü sıraya göre numaralandırılır, ancak herhangi bir sırayla kullanılabilir ve tekrarlanabilir:
echo "foobarbaz" | sed -r 's/^foo(.*)b(.)z$/\2 \1 \2/'
"a a" çıktılar.
GNU'nuz varsa grep
(OS X dahil BSD'de de çalışabilir):
echo "$string" | grep -Po '\d+'
veya aşağıdakiler gibi varyasyonlar:
echo "$string" | grep -Po '(?<=\D )(\d+)'
Bu -P
seçenek Perl Uyumlu Düzenli İfadeleri etkinleştirir. Bkz. man 3 pcrepattern
Veya man
3 pcresyntax
.
sed
, -r
seçeneği (veya -E
OS X, IIRC için) kullanıyorsanız, parantezlerden kaçmanız gerekmez. Aradaki fark, temel düzenli ifadeler ile genişletilmiş düzenli ifadeler ( -r
) arasındadır.
Sed'de dokuz hatırlanmış desen var, ancak normal ifadenin bölümlerini hatırlamak için kaçan parantezleri kullanmanız gerekiyor.
Örnekler ve daha fazla ayrıntı için buraya bakın
sed -e 's/version=\(.+\)/\1/' input.txt
bu yine de tüm girişin çıktısını verecektir. txt
\+
bunun yerine yazmak zorundasınız +
. Ve insanların neden -e
sadece bir sed komutu için kullandıklarını anlamıyorum .
sed -e -n 's/version=\(.+\)/\1/p' input.txt
bkz: mikeplate.com/2012/05/09/…
sed -E
Perl / Java / JavaScript / Go / her türlü aromaya çok daha yakın görünen "modern" veya "genişletilmiş" düzenli ifadeleri kullanmanızı öneririm . ( grep -E
Veya ile karşılaştır egrep
.) Varsayılan sözdiziminde bu garip kaçış kuralları vardır ve "eski" kabul edilir. İkisi arasındaki farklar hakkında daha fazla bilgi için çalıştırın man 7 re_format
.
grep kullanabilirsiniz
grep -Eow "[0-9]+" file
o
seçenek var - unixhelp.ed.ac.uk/CGI/man-cgi?grep : -o, --sadece eşleme Yalnızca eşleşen bir satırın PATTERN ile eşleşen kısmını göster
grep -Eow -e "[0-9]+" -e "[abc]{2,3}"
iki grepten gelen borular dışında, bu iki ifadenin bir satırda nasıl olmasını gerektirebileceğinizi bilmiyorum (eğer bir kalıp bir satırda birden fazla eşleşirse yine de çalışmayabilir) ).
Bu cevap herhangi bir sayı grubu ile çalışır. Misal:
$ echo 'Num123that456are7899900contained0018166intext' |
> sed -En 's/[^0-9]*([0-9]{1,})[^0-9]*/\1 /gp'
123 456 7899900 0018166
Sed'e yalnızca yakalanan grupları vermesini söylemenin bir yolu var mı?
Evet. tüm metni yakalama grubuyla değiştir:
$ 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.
Veya genişletilmiş sözdizimi ile (daha az geri tırnak ve + kullanımına izin ver):
$ echo 'Number 123 in text' | sed -E 's/[^0-9]*([0-9]+)[^0-9]*/\1/'
123
Numara olmadığında orijinal metnin yazdırılmasını önlemek için şunu kullanın:
$ echo 'Number xxx in text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1/p'
Ve birkaç sayıyı eşleştirmek (ve ayrıca yazdırmak):
$ echo 'N 123 in 456 text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1 /gp'
123 456
Herhangi bir sayı çalıştırması için çalışır:
$ 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
Hangi grep komutuna çok benzer:
$ str='Test Num(s) 123 456 7899900 contained as0018166df in text'
$ echo "$str" | grep -Po '\d+'
123
456
7899900
0018166
ve desen:
/([\d]+)/
Sed, '\ d' (kısayol) sözdizimini tanımıyor. Yukarıda kullanılan ascii eşdeğeri [0-9]
tam olarak eşdeğer değildir. Tek alternatif çözüm bir karakter sınıfı kullanmaktır: '[[: digit:]] `.
Seçilen cevap bir çözüm oluşturmak için bu tür "karakter sınıflarını" kullanır:
$ str='This is a sample 123 text and some 987 numbers'
$ echo "$str" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
Bu çözüm yalnızca (tam olarak) iki basamaklı basamak için geçerlidir.
Elbette, cevap kabuğun içinde yürütülürken, bu cevabı kısaltmak için birkaç değişken tanımlayabiliriz:
$ 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"
Ancak, daha önce açıklandığı gibi, bir s/…/…/gp
komut kullanmak daha iyidir:
$ 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
Bu, hem tekrarlanan basamak çalışmalarını hem de bir kısa (er) komutu yazmayı kapsayacaktır.
Soruda verilen paternin sadece örnek olması gerektiğine ve amacın herhangi bir paternle eşleşmek olduğuna inanıyorum .
Desen alanına yeni satırın eklenmesine izin veren GNU uzantısına sahip bir sed varsa , bir öneri:
> 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
Bu örnekler CYGWIN ile tcsh ile (evet, yanlış kabuk olduğunu biliyorum ). (Düzenleme: Bash için, grubu ve çevresindeki boşlukları kaldırın =.)
+
, bundan kaçmanız veya -r
seçeneği kullanmanız gerekir ( -E
OS X için). Ayrıca kullanabilirsiniz \{1,\}
(ya -r
ya -E
kaçması olmadan).
Vazgeç ve Perl kullan
Yana sed
kesmek yok, 'adil öyle en azından, Perl havlu atmak ve kullanmasına izin LSB ise grep
GNU uzantıları değildir :-)
Eşleşen parçanın tamamını yazdırın, eşleşen grup veya gözetleme gerekmez:
cat <<EOS | perl -lane 'print m/\d+/g'
a1 b2
a34 b56
EOS
Çıktı:
12
3456
Satır başına tek eşleme, genellikle yapılandırılmış veri alanları:
cat <<EOS | perl -lape 's/.*?a(\d+).*/$1/g'
a1 b2
a34 b56
EOS
Çıktı:
1
34
Lookbehind ile:
cat <<EOS | perl -lane 'print m/(?<=a)(\d+)/'
a1 b2
a34 b56
EOS
Birden çok alan:
cat <<EOS | perl -lape 's/.*?a(\d+).*?b(\d+).*/$1 $2/g'
a1 c0 b2 c0
a34 c0 b56 c0
EOS
Çıktı:
1 2
34 56
Satır başına birden fazla eşleşme, genellikle yapılandırılmamış veriler:
cat <<EOS | perl -lape 's/.*?a(\d+)|.*/$1 /g'
a1 b2
a34 b56 a78 b90
EOS
Çıktı:
1
34 78
Lookbehind ile:
cat EOS<< | perl -lane 'print m/(?<=a)(\d+)/g'
a1 b2
a34 b56 a78 b90
EOS
Çıktı:
1
3478
Deneyin
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"
Bunu cygwin'in altına aldım:
$ (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'nin istediği şey bu değil (grupları yakalama) ancak sayıları kullanarak şunları elde edebilirsiniz:
S='This is a sample 123 text and some 987 numbers'
echo "$S" | sed 's/ /\n/g' | sed -r '/([0-9]+)/ !d'
Aşağıdakileri verir:
123
987
sed
, işaretli genişletilmiş düzenli ifadeleri açması gerektiğini unutmayın-E
.