2013-06-24 2 views
0

В настоящее время я пытаюсь извлечь ВСЕ подходящие выражения из текста, например. выглядит так и помещает их в массив.Shell: извлекать слова, соответствующие шаблону, но игнорировать обходящее выражение

aaaaaaaaa${bbbbbbb}ccccccc${dddd}eeeee 
ssssssssssssssssss${TTTTTT}efhsekfh ej 
348653jlk3jß1094utß43t59ßgöelfl,-s-fko 

Выражение соответствия похоже на это: ${}. Остерегайтесь, что мне нужно полное выражение, а не только слово между этим выражением! Так что в этом случае результат должен быть массивом, который содержит:

${bbbbbbb} 
${dddd} 
${TTTTTTT} 

Проблемы я наткнулся и не мог решить:

  1. Он должен НЕ признает это в целом ${bbbbbbb}ccccccc${dddd}, но каждый для его собственный
  2. grep -o не установлен на старой машине, Perl также не допускается!
  3. Многие команды, например. BASH_REMATCH передает только целую строку или первое вхождение выражения, а не все соответствующие выражения в строке!

Упомянутая модель \${[^}]*}, кажется, работает частично, так как он может извлечь первое вхождение выражения, однако это всегда omitts того следующей после этого, если он находится в той же строке текста. Мне нужно, чтобы все соответствующие выражения находились в строке, а не только первая.

+0

вам нужно не жадное совпадение: ['perl -nE 'say $ 1 while /\${([^}]*)}/g''](http://ideone.com/ZRsh6M) – jfs

ответ

0

Поскольку это прослушивало меня много, я спросил прямо на сайте www.unix.com и был любезно предоставлен решение, которое подходит для моей старой оболочки. Так что если кто-нибудь есть такая же проблема вот решение:

line='aaaa$aa{yyy}aaa${important}xxxxxxxx${important2}oo{o$}oo$oo${importantstring3}' 
IFS=\$ read -a words <<< "$line" 
regex='^(\{[^}]+})' 
for e in "${words[@]}"; do 
    if [[ $e =~ $regex ]]; then 
     echo "\$${BASH_REMATCH[0]}"; 
    fi; 
done 

который печатает то следующий - даже не получая встревожено случайными возникновениями $ и { или } между синтаксический правильными выражениями:

${important} 
${important2} 
${importantstring3} 

Я обновил полное решение после того, как получил еще одно обновление с форумов: теперь он также игнорирует это: aaa$aa{yyy}aaaa - который он ранее печатал как $ {yyy} - но который он должен полностью игнорировать, так как есть символы между $ и {. Теперь с дополнительным привязкой в ​​начале regexp он работает так, как ожидалось.

Я только что нашел еще одну проблему: теоретически используя вышеприведенный подход, я все равно получаю неверный вывод, если строка чтения выглядит так: line='{ccc}aaaa${important}aaa'. IFS разделит его, и REGEX будет соответствовать {ccc}, хотя это не было знаком $ спереди. Это субоптимально.
Однако следующий подход может решить его: после получения BASH_REMATCH мне нужно будет выполнить поиск в исходной строке - тот, который я дал IFS - для этого точного выражения ${ccc} - с той разницей, что включен $! И только если он находит это точное совпадение, только тогда он считается действительным совпадением; в противном случае его следует игнорировать. Вид обратного метода поиска ...

Обновлено - добавить этот обратный поиск игнорировать ловушку на начало строки:

pattern="\$${BASH_REMATCH[0]}"; 
searchresult=""; 
searchresult=`echo "$line" | grep "$pattern"`; 

if [ "$searchresult" != "" ]; then echo "It was found!"; fi; 

пренебрежимо вопрос: Если строка выглядит следующим образом line='{ccc}aaaaaa${ccc}bbbbb' было бы признайте первым{ccc} в качестве действительного соответствия (хотя это не так) и распечатайте его, потому что в обратном поиске найдено second${ccc}. Хотя это не предназначено, это не имеет значения для моей конкретной цели, поскольку это подразумевает, что этот шаблон действительно существует хотя бы один раз в одной строке.

1

Вы можете разделить строку на любой из символов $, {, }:

$ s='...blaaaaa${blabla}bloooo${bla}bluuuuu...' 
$ echo "$s" 
...blaaaaa${blabla}bloooo${bla}bluuuuu... 
$ IFS='${}' read -ra words <<< "$s" 
$ for ((i=0; i<${#words[@]}; i++)); do printf "%d %s\n" $i "${words[i]}"; done 
0 ...blaaaaa 
1 
2 blabla 
3 bloooo 
4 
5 bla 
6 bluuuuu... 

Так что, если вы пытаетесь извлечь слова в фигурных скобках:

$ for ((i=2; i<${#words[@]}; i+=3)); do printf "%d %s\n" $i "${words[i]}"; done 
2 blabla 
5 bla 

Если вышеуказанное не подходит, grep будет работать:

$ echo '...blaaaaa${blabla}bloooo${bla}bluuuuu...' | grep -o '\${[^}]\+}' 
${blabla} 
${bla} 

Вы все еще не сказали нам, какой именно результат вы хотите.

+0

Здравствуйте, спасибо за ваш ответ, но в этом случае это не сработает, так как требуется всего выражение «$ {...}», а не только слово между скобками. При использовании подхода IFS невозможно определить правильные слова после помещения их в массив, поскольку они все удалили свои скобки или «разделители». Возможно, это было недостаточно ясно в моем посте, извините. – Malvin

+0

Это второе решение будет именно тем, что мне нужно, если бы у меня была опция «grep -o». К сожалению, я получаю «незаконный вариант», и я все равно должен найти способ сделать это. Достаточно смешно, что большинство других команд соответствуют только целым строкам, поэтому, если я получаю 2 или более из этих шаблонов в одной строке, он пропустит их и отобразит только первое вхождение. – Malvin