2016-05-30 2 views
0

Мне нужно заменить «незначительные» части имени. Это нужно сделать в сценарии bash. Для этого мне нужно удалить средние слова «VAN», «DEN», «DE» и «DER».

Чтобы сделать это, я использую встроенную программу замены (задача сводится к 2-х линий):

line="STIG VAN DE WYNKELE"; 
line=${line//@(' VAN '|' DEN '|' DE '|' DER ')/' '}; 
echo $line; 

Выход:

STIG DE WYNKELE 

Ожидаемый результат:

STIG WYNKELE 

Кажется, что @ (...) соответствует одному из средних слов, удаляя все вхождения этого среднего слова, но оно не совпадает с RS.

Вопрос: Я делаю что-то не так в своем синтаксисе? Если нет, как бы удалить эти слова? sed требует файлов, а мой ввод - переменная, а измененный текст также должен храниться в переменной. (строка $ должна быть изменена)

+1

'sed' не требует файлов, это потоковый редактор. 'foo = $ (echo" $ foo "| sed ...)' является общей идиомой. –

+0

Обычный, но обычно не нужен, если '$ foo' короткий. – chepner

ответ

3

bash не возвращаться назад. Во-первых, он находит VAN на входе:

STIG VAN DE WYNKELE 
    ^^^^^| 

(где | представляет свой указатель во время сканирования).

После замены VAN с , у вас есть

STIG DE WYNKELE 
    | 

Вы заметите, что DE не найден в строке, начиная с D; пространство, которое вы только что вставили, не проверяется bash.

Вместо уронить ведущее место из каждого шаблона, и удалить матч вместо того, чтобы заменить его пробелом:

echo "${line//@('VAN '|'DEN '|'DE '|'DER ')}" 

Конечно, проблема состоит в том, что теперь вы могли бы опустить совпадение, которое встречается в конце слова. Нельзя избегать этого с одним матчем; вместо этого, сделать несколько замен в цикле:

for word in VAN DEN DE DER; do 
    line=${line// $word/} 
done 
+0

Это решило проблему и выглядит как лучший способ сделать это без каких-либо побочных эффектов, спасибо! – Bertware

+0

Это возможно с одним совпадением, но только с внешними элементами (не поддерживается в bash). – choroba

0

Вам не нужно extglob. Вы можете просто использовать параметр расширения:

${line/ */} 

Пример:

$ line="STIG VAN DE WYNKELE" 
$ echo ${line/ */} 
STIG WYNKELE 
4

Вы должны установить опцию extglob. Также удалите кавычки и переместите пространство вне альтернативы. Вы можете сократить выражение дальше:

#!/bin/bash 
line="STIG VAN DE DEN DER WYNKELE" 
shopt -s extglob 
line=${line//@(VAN|DE?([NR])) } 
echo "$line" 

По двойному quotting $ линии в последней строке, вы можете увидеть, были ли пробела правильно удалены.

+0

'Need' - сильное слово. Imo не нужно использовать 'extglob' здесь – hek2mgl

+0

@ hek2mgl: Чтобы использовать' @ (... | ...) ', вам нужно ... – choroba

+0

У вас, верно, я не обратил внимания на это, так как это включен по умолчанию на моем ящике. Спасибо! – hek2mgl

0

С AWK:

echo $line | awk '{ if ($2 == "VAN" || $2 == "DEN" || $2 =="DE" || $2=="DER" ) $2=""; if ($3 == "VAN" || $3== "DEN" || $3 =="DE" || $3=="DER" ) $3="" ; print }' 
Смежные вопросы