Sed редкий-разделитель (кроме & |/?...)

Я должен применить команду Unix sed к строке (может содержать #,!,/,?, &, @и все остальные символы), которые может содержать все типы символов (&, |,!,/,?...)

Является ли это сложным разделителем (с двумя символами?), который позволяет исключить ошибку:

sed: -e expression #1, char 22: unknown option to `s'

Заранее спасибо

Ответ 1

В sed нет такой опции для мультисимвольных разделителей выражений, но я сомневаюсь вам это нужно. Символ разделителя не должен встречаться в шаблоне, но если он появляется в обрабатываемой строке, это не проблема. И если вы не делаете что-то чрезвычайно странное, всегда будет какой-то символ, который не отображается в вашем шаблоне поиска, который может служить разделителем.

Ответ 2

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

По крайней мере на GNU sed вы можете использовать непечатаемый символ, который очень маловероятен для существования в вашем шаблоне в качестве разделителя. Например, если ваша оболочка Bash:

$ echo '|||' | sed s$'\001''|'$'\001''/'$'\001''g'

В этом примере Bash заменяет $'\001' символом с восьмеричным значением 001 - в ASCII это SOH символ (начало заголовка).

Поскольку такие символы являются управляющими/непечатаемыми символами, сомнительно, что они будут существовать в шаблоне. Если, то есть, вы делаете что-то странное, как изменение двоичных файлов, или файлы Unicode без правильных настроек локали.

Ответ 3

Другой способ сделать это - использовать замену параметров Shell.

${parameter/pattern/replace}  # substitute replace for pattern once

или

${parameter//pattern/replace}  # substitute replace for pattern everywhere

Вот довольно сложный пример, сложный с sed:

$ parameter="Common sed delimiters: [sed-del]"
$ pattern="\[sed-del\]"
$ replace="[/_%:\\@]"
$ echo "${parameter//$pattern/replace}"

результат:

Common sed delimiters: [/_%:\@]

Однако: Это работает только с параметрами bash, а не с файлами, где sed excel.

Ответ 4

Вам нужен объект вложенного ограничителя, который предлагает Perl. Это позволяет использовать такие вещи, как сопоставление, подстановка и транслитерация, не беспокоясь о том, что разделитель включен в ваше содержимое. Поскольку perl является надмножеством sed, вы можете использовать его для любого использования sed.

Рассмотрим это:

$ perl -nle 'print if /something/' inputs

Теперь, если ваш something содержит косую черту, у вас есть проблема. Способ исправить это - изменить разделитель, предпочтительно на брекетинг. Так, например, вы могли бы иметь что угодно, как в переменной оболочки WHEREVER (при условии, что баланс сбалансирован), который интерпретируется оболочкой до того, как Perl даже вызывается здесь:

 $ perl -nle "print if m($WHATEVER)" /usr/share/dict/words

Это работает, даже если вы правильно ввели parens в $WHATEVER. Четыре пары брекетинга, которые правильно вложены в Perl, равны < >, ( ), [ ] и { }. Они позволяют произвольное содержимое включать разделитель, если этот разделитель сбалансирован.

Если он не сбалансирован, тогда не используйте разделитель вообще. Если шаблон находится в переменной Perl, вам не нужно использовать оператор сопоставления, если вы используете оператор =~, поэтому:

$whatever = "some arbitrary string ( / # [ etc";
if ($line =~ $whatever) { ... }

Ответ 5

С помощью Джима Льюиса я, наконец, сделал тест перед использованием sed:

if [ `echo $1 | grep '|'` ]; then
    grep ".*$1.*:" $DB_FILE  | sed "[email protected]^.*$1*.*\(:\)@@ "
else
    grep ".*$1.*:" $DB_FILE  | sed "s|^.*$1*.*\(:\)|| "
fi

Спасибо за помощь

Ответ 6

Ого. Я полностью не знал, что вы можете использовать любого персонажа в качестве разделителя. По крайней мере, в половине случаев я использую sed и BREs на своих путях, фрагментах кода, мусорных символах, подобных вещах. Я в конечном итоге с кучей ужасно нечитаемых побегов, которые я даже не уверен, не умрут в какой-то комбинации, о которой я не думал. Но если вы можете исключить только некоторый класс символов (или только один символ)

echo '#01Y $#1+!' | sed -e 'sa$#1+ashita' -e 'su#01YuHolyug'

> > > Holy shit! Это намного проще.

Ответ 7

Удаление разделителя inline для BASH для синтаксического анализа является громоздким и трудным для чтения (хотя разделитель действительно нуждается в ускорении для выгоды sed, когда он впервые использовался, для выражения).

Чтобы собрать thkala ответ и user4401178 комментарий:

DELIM=$(echo -en "\001");
sed -n "\\${DELIM}${STARTING_SEARCH_TERM}${DELIM},\\${DELIM}${ENDING_SEARCH_TERM}${DELIM}p" "${FILE}"

В этом примере возвращаются все результаты, начиная с ${STARTING_SEARCH_TERM} до ${ENDING_SEARCH_TERM}, которые не соответствуют символу SOH (начало заголовка) с кодом ASCII 001.