Jawaban:
Kunci untuk membuat ini bekerja adalah untuk mengatakan sed
untuk mengecualikan apa yang tidak Anda inginkan sebagai output serta menentukan apa yang Anda inginkan.
string='This is a sample 123 text and some 987 numbers'
echo "$string" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
Ini mengatakan:
-n
)p
)Secara umum, dalam sed
Anda menangkap grup menggunakan tanda kurung dan output apa yang Anda ambil menggunakan referensi kembali:
echo "foobarbaz" | sed 's/^foo\(.*\)baz$/\1/'
akan menampilkan "bar". Jika Anda menggunakan -r
( -E
untuk OS X) untuk regex yang diperluas, Anda tidak perlu keluar dari tanda kurung:
echo "foobarbaz" | sed -r 's/^foo(.*)baz$/\1/'
Mungkin ada hingga 9 kelompok penangkapan dan referensi belakang mereka. Referensi belakang diberi nomor sesuai urutan munculnya kelompok, tetapi mereka dapat digunakan dalam urutan apa pun dan dapat diulang:
echo "foobarbaz" | sed -r 's/^foo(.*)b(.)z$/\2 \1 \2/'
menghasilkan "bilah a".
Jika Anda memiliki GNU grep
(mungkin juga berfungsi di BSD, termasuk OS X):
echo "$string" | grep -Po '\d+'
atau variasi seperti:
echo "$string" | grep -Po '(?<=\D )(\d+)'
The -P
pilihan memungkinkan Perl Regular Expressions Kompatibel. Lihat man 3 pcrepattern
atau man
3 pcresyntax
.
sed
contoh, jika Anda menggunakan -r
opsi (atau -E
untuk OS X, IIRC) Anda tidak perlu keluar dari tanda kurung. Perbedaannya adalah antara ekspresi reguler dasar dan ekspresi reguler lanjutan ( -r
).
Sed memiliki hingga sembilan pola yang diingat tetapi Anda harus menggunakan tanda kurung yang lolos untuk mengingat bagian dari ekspresi reguler.
Lihat di sini untuk contoh dan lebih detail
sed -e 's/version=\(.+\)/\1/' input.txt
ini masih akan menampilkan seluruh input.txt
\+
alih-alih +
. Dan saya tidak mengerti mengapa orang -e
hanya menggunakan satu perintah sed.
sed -e -n 's/version=\(.+\)/\1/p' input.txt
lihat: mikeplate.com/2012/05/09/...
sed -E
menggunakan apa yang disebut ekspresi reguler "modern" atau "extended" yang terlihat jauh lebih dekat dengan Perl / Java / JavaScript / Go / apa pun rasanya. (Bandingkan dengan grep -E
atau egrep
.) Sintaks default memiliki aturan pelarian yang aneh dan dianggap "usang". Untuk info lebih lanjut tentang perbedaan antara keduanya, jalankan man 7 re_format
.
Anda bisa menggunakan grep
grep -Eow "[0-9]+" file
o
pilihan ada di sana - unixhelp.ed.ac.uk/CGI/man-cgi?grep : -o, --only-matching Tampilkan hanya bagian dari garis yang cocok yang cocok dengan POLA
grep -Eow -e "[0-9]+" -e "[abc]{2,3}"
Saya tidak tahu bagaimana Anda dapat mengharuskan kedua ekspresi itu berada di satu baris selain dari perpipaan dari grep sebelumnya (yang masih bisa tidak bekerja jika salah satu pola cocok lebih dari satu kali pada satu baris) ).
Jawaban ini berfungsi dengan jumlah kelompok digit apa pun. Contoh:
$ echo 'Num123that456are7899900contained0018166intext' |
> sed -En 's/[^0-9]*([0-9]{1,})[^0-9]*/\1 /gp'
123 456 7899900 0018166
Apakah ada cara untuk mengatakan sed kepada output hanya kelompok yang ditangkap?
Iya. ganti semua teks dengan grup tangkap:
$ 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.
Atau dengan sintaks yang diperluas (kurangi backquotes dan izinkan penggunaan +):
$ echo 'Number 123 in text' | sed -E 's/[^0-9]*([0-9]+)[^0-9]*/\1/'
123
Untuk menghindari pencetakan teks asli ketika tidak ada nomor, gunakan:
$ echo 'Number xxx in text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1/p'
Dan untuk mencocokkan beberapa angka (dan juga mencetaknya):
$ echo 'N 123 in 456 text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1 /gp'
123 456
Itu bekerja untuk setiap hitungan digit berjalan:
$ 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
Yang sangat mirip dengan perintah grep:
$ str='Test Num(s) 123 456 7899900 contained as0018166df in text'
$ echo "$str" | grep -Po '\d+'
123
456
7899900
0018166
dan pola:
/([\d]+)/
Sed tidak mengenali sintaks '\ d' (pintasan). Setara ascii yang digunakan di atas [0-9]
tidak persis sama. Satu-satunya solusi alternatif adalah dengan menggunakan kelas karakter: '[[: digit:]] `.
Jawaban yang dipilih menggunakan "kelas karakter" untuk membangun solusi:
$ str='This is a sample 123 text and some 987 numbers'
$ echo "$str" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
Solusi itu hanya bekerja untuk dua digit digit.
Tentu saja, ketika jawaban dieksekusi di dalam shell, kita dapat mendefinisikan beberapa variabel untuk mempersingkat jawaban tersebut:
$ 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"
Tapi, seperti yang sudah dijelaskan, menggunakan s/…/…/gp
perintah lebih baik:
$ 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
Itu akan mencakup kedua digit yang berulang dan menulis perintah (er) pendek.
Saya percaya pola yang diberikan dalam pertanyaan itu hanya dengan contoh saja, dan tujuannya adalah untuk mencocokkan pola apa pun .
Jika Anda memiliki sed dengan ekstensi GNU yang memungkinkan penyisipan baris baru dalam ruang pola, satu saran adalah:
> 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
Contoh-contoh ini dengan tcsh (ya, saya tahu itu shell yang salah) dengan CYGWIN. (Edit: Untuk bash, hapus set, dan spasi di sekitar =.)
+
, Anda harus menghindarinya atau menggunakan -r
opsi ( -E
untuk OS X). Anda juga dapat menggunakan \{1,\}
( -r
atau -E
tanpa melarikan diri).
Menyerah dan menggunakan Perl
Karena sed
tidak memotongnya, mari kita membuang handuk dan menggunakan Perl, setidaknya itu adalah LSB sedangkan grep
ekstensi GNU tidak :-)
Cetak seluruh bagian yang cocok, tidak perlu grup yang cocok atau yang terlihat di belakang:
cat <<EOS | perl -lane 'print m/\d+/g'
a1 b2
a34 b56
EOS
Keluaran:
12
3456
Kecocokan tunggal per baris, bidang data yang sering terstruktur:
cat <<EOS | perl -lape 's/.*?a(\d+).*/$1/g'
a1 b2
a34 b56
EOS
Keluaran:
1
34
Dengan melihat di belakang:
cat <<EOS | perl -lane 'print m/(?<=a)(\d+)/'
a1 b2
a34 b56
EOS
Banyak bidang:
cat <<EOS | perl -lape 's/.*?a(\d+).*?b(\d+).*/$1 $2/g'
a1 c0 b2 c0
a34 c0 b56 c0
EOS
Keluaran:
1 2
34 56
Beberapa kecocokan per baris, seringkali data tidak terstruktur:
cat <<EOS | perl -lape 's/.*?a(\d+)|.*/$1 /g'
a1 b2
a34 b56 a78 b90
EOS
Keluaran:
1
34 78
Dengan melihat di belakang:
cat EOS<< | perl -lane 'print m/(?<=a)(\d+)/g'
a1 b2
a34 b56 a78 b90
EOS
Keluaran:
1
3478
Mencoba
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"
Saya mendapatkan ini di bawah 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
$
Bukan itu yang diminta OP (menangkap grup) tetapi Anda dapat mengekstraksi angka menggunakan:
S='This is a sample 123 text and some 987 numbers'
echo "$S" | sed 's/ /\n/g' | sed -r '/([0-9]+)/ !d'
Memberikan yang berikut:
123
987
sed
harus mengaktifkan ekspresi reguler yang diperluas dengan-E
bendera.