Відповіді:
Ключовим фактором для роботи є те, щоб 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/'
виводить "бар а".
Якщо у вас є GNU grep
(він також може працювати в BSD, включаючи OS X):
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 має до дев'яти запам'ятовуваних шаблонів, але вам потрібно використовувати скочені дужки, щоб запам'ятати частини регулярного виразу.
Дивіться тут приклади та більш детальну інформацію
sed -e 's/version=\(.+\)/\1/' input.txt
це все одно виведе весь input.txt
\+
замість +
. І я не розумію, чому люди використовують -e
лише одну команду sed.
sed -e -n 's/version=\(.+\)/\1/p' input.txt
див .: mikeplate.com/2012/05/09/…
sed -E
використовувати так звані "сучасні" або "розширені" регулярні вирази, які набагато ближче до Perl / Java / JavaScript / Go / будь-яких смаків. (Порівняйте з grep -E
або egrep
.) У синтаксисі за замовчуванням є ті дивні правила, що виходять, і вважається "застарілим". Щоб отримати докладнішу інформацію про відмінності між ними, запустіть man 7 re_format
.
можна використовувати греп
grep -Eow "[0-9]+" file
o
опція є - unixhelp.ed.ac.uk/CGI/man-cgi?grep : -o, - тільки відповідна Показати лише ту частину лінії, що відповідає, що відповідає PATTERN
grep -Eow -e "[0-9]+" -e "[abc]{2,3}"
я не знаю, як ви могли б вимагати, щоб ці два вирази були в одному рядку, окрім конфігурації попереднього файлу grep (який все ще не може працювати, якщо будь-який візерунок збігається більше, ніж один раз у рядку ).
Ця відповідь працює з будь-яким числом цифрних груп. Приклад:
$ 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' (ярлик). Еквівалент ascii, використаний вище [0-9]
, не зовсім еквівалентний. Єдине альтернативне рішення - використовувати клас символів: '[[: цифра:]] `.
Вибрана відповідь використовує такі "класи символів" для побудови рішення:
$ str='This is a sample 123 text and some 987 numbers'
$ echo "$str" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
Це рішення працює лише для (точно) двох циклів цифр.
Звичайно, оскільки відповідь виконується всередині оболонки, ми можемо визначити пару змінних для скорочення такої відповіді:
$ 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
Це охоплюватиме неодноразові запуски цифр та написання короткої (ер) команди.
Я вважаю, що модель, подана у питанні, була лише прикладом, і мета полягала в тому, щоб відповідати будь-якій схемі.
Якщо у вас є sed з розширенням GNU, що дозволяє вставити нову рядок у простір шаблону, одна пропозиція:
> 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
Ці приклади з tcsh (так, я знаю, що це неправильна оболонка) з CYGWIN. (Редагувати: для 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
Один матч на рядок, часто структуровані поля даних:
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
Кілька збігів на рядок, часто неструктуровані дані:
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
$
ОП не вимагало (захоплення груп), але ви можете витягувати номери, використовуючи:
S='This is a sample 123 text and some 987 numbers'
echo "$S" | sed 's/ /\n/g' | sed -r '/([0-9]+)/ !d'
Дає наступне:
123
987
sed
ввімкнути розширені регулярні вирази з-E
прапором.