жемчуг regex заменяющий глобально, когда глобальный не выбранный

Можно расширить строки в ударе с помощью обратной косой черты в конце строки как это:

export PATH=/path/A:\
/path/B:\
/path/C

Обратите внимание на то, что отсутствие пробела важно здесь.

2
01.10.2011, 07:26
2 ответа

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

Для замены просто первого вхождения в файле можно добавить -0 опция, которая устанавливает входной разделитель записей на нулевой символ и заставляет жемчуг считать целый файл прежде, чем сделать замену.

1
27.01.2020, 22:15

s/$f/$g/ заменяет первое вхождение $f $g на каждой строке. Если Вы хотите заменить только первое вхождение $f в целом файле необходимо сказать так. Это - то, в чем Вы в конечном счете выполнили sed с 0,/$f/ s/$f/$g/ (замена $f $g до и включая первое вхождение $f). В Perl можно записать это в более подробном, но более легком для понимания пути как это (примечание: посмотрите ниже для заключения в кавычки проблем):

perl -i -pe 'if ($n==0) {s/$f/$g/; $n=1;} elsif ($n==1) {s/$f/$h/; $n=2}'

Ваш код страдает от многочисленных проблем заключения в кавычки; Вы столкнетесь с проблемой, если Ваши имена файлов будут содержать пробел, globbing символы или непечатные символы (такие как последовательности байта, которые не существуют в текущей локали). К счастью, эти проблемы легко устранить.

Во-первых, некоторые универсальные проблемы оболочки. Всегда подстановки переменных двойной кавычки "$foo" и замены команды "$(foo)" если Вы не знаете, почему необходимо оставить их, закрыл кавычки. Если Вы оставляете их, закрыл кавычки, результат разделяется на отдельные слова везде, где он содержит пробел, и каждое слово рассматривают как шаблон шарика. Таким образом, если переменная, оказывается, не содержит разделенный от пробела список шаблонов шарика, поместите двойные кавычки вокруг этого. Кроме того, я рекомендую использовать $(…) вместо `…`; они эквивалентны, за исключением того, что вложенное заключение в кавычки внутри `…` ненадежно (также, ` легко перепутан с ').

Не анализируйте вывод ls. Если необходимо действовать на все файлы в каталоге, оболочка имеет встроенную конструкцию, которая работает: globbing. Вместо $(ls /path/to/directory), записать /path/to/directory/*. Это генерирует имена файлов с путем к каталогу; это почти всегда, в чем Вы нуждаетесь так или иначе, и если Вы не делаете, можно или звонить cd заранее или снимите все или часть каталога. Ниже, я использую ${f#*/*/}, что означает $f с самым коротким соответствием префикса */*/ неизолированный.

for f in .templates/template_text/*; do
  g=$(cat "$f")
  h=$(cat ".templates/template_html/${f#*/*/}")
  find to_process/ -type f …
done

С find, можно использовать более простую конструкцию -exec, хотя -print0 объединенный с xargs -0 работы также. Не использовать xargs без -0, поскольку это ожидает вход, заключенный в кавычки специфическим способом который find не производит.

find to_process/ -type f -exec perl … {} +

Следующий выпуск - то, что Вы вставляете строки $f, $g и $h непосредственно в Вашем sed или регулярном выражении жемчуга. Это неправильно: они переменная не содержат регулярное выражение с разделителем (/ в обоих случаях) заключенный в кавычки. С sed необходимо было бы сделать передачу заключения в кавычки на строках, добавив обратную косую черту перед любой из /*.\[ в $f и перед любой из \&/ в $g и $h. С Perl существует более простой путь: передайте значения через среду и обязательно скажите Perl, который, что Вы имеете, строка и не regexp.

export f g h
find to_process/ -type f -exec perl -i -e '
    if ($n==0) {s/\Q$ENV{f}/$ENV{g}/; $n=1;}
    elsif ($n==1) {s/\Q$ENV{f}/$ENV{h}/; $n=2}}
' {} +
1
27.01.2020, 22:15

Теги

Похожие вопросы