Подтвердить что ты не робот

Как передать переменную, содержащую слэши, для sed

Как передать переменную, содержащую косую черту, как шаблон для sed?

Например, если у меня есть следующая переменная:

var="/Users/Documents/name/file"

Я хочу передать его в sed так:

sed "s/$var/replace/g" "$file"

Однако я получаю ошибки. Как я могу обойти проблему?

4b9b3361

Ответ 1

Используйте альтернативный разделитель регулярных выражений, так как sed позволяет использовать любой разделитель (включая управляющие символы):

sed "s~$var~replace~g" $file

Ответ 2

Чистый ответ bash: используйте расширение параметра для обратного слэша - сбрасывайте любые слэши в переменной:

var="/Users/Documents/name/file"
sed "s/${var//\//\\/}/replace/g" $file

Ответ 3

Другой способ сделать это, хотя и более уродливым, чем ответ анубхавы, заключается в том, чтобы избежать всех обратных косых черт в var с помощью другой команды sed:

var=$(echo "$var" | sed 's/\//\\\//g')

тогда это будет работать:

sed "s/$var/replace/g" $file

Ответ 4

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

var="/Users/Documents/name/file"

вы можете использовать символ octothorpe, который подходит для случая (или любого другого символа, который не является / для удобства использования)

sed "s#$var#replace#g" 

или

  sed 's#$'$var'#replace#g'

это подходит, когда переменная не содержит пробелов

или

sed 's#$"'$var'"#replace#g'

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

Ответ 5

Это старый вопрос, но ни один из ответов здесь не описывает операции, кроме s/from/to/ в деталях.

Общая форма выражения sed

*address* *action*

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

sed '1,4d' file

удалит строки с 1 по 4 (адрес - диапазон номеров строк 1,4 а действие - команда d delete); а также

sed '/ick/,$s/foo/bar/' file

заменит первое вхождение foo на bar в любой строке между первым совпадением в регулярном выражении ick и концом файла (адрес - диапазон /ick/,$ а действие - команда s substitute s/foo/bar/).

В этом контексте, если ick пришел из переменной, вы можете сделать

sed "/$variable/,\$s/foo/bar/"

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

Суть в том, чтобы использовать другой разделитель (где, очевидно, вам нужно иметь возможность использовать символ, который не может присутствовать в значении переменной), но в отличие от случая s%foo%bar%, вам также необходимо использовать обратную косую черту перед разделителем, если Вы хотите использовать другой разделитель, чем по умолчанию /:

sed "\\%$variable%,\$s/foo/bar/" file

(внутри одинарных кавычек, очевидно, достаточно одного обратного слеша); или вы можете отдельно избежать каждой косой черты в значении. Этот конкретный синтаксис только Bash:

sed "/${variable//\//\\/}/,\$s/foo/bar/" file

или если вы используете другую оболочку, попробуйте

escaped=$(echo "$variable" | sed 's%/%\\/%g')
sed "s/$escaped/,\$s/foo/bar/" file

Для ясности, если бы $variable содержал строку 1/2 вышеприведенные команды были бы эквивалентны

sed '\%1/2%,$s/foo/bar/' file

в первом случае и

sed '/1\/2/,$s/foo/bar/' file

во-вторых.

Ответ 6

Альтернативный разделитель работает только тогда, когда есть необходимость в поиске и замене. В таких случаях, когда необходимо удалить строки из файла на основе слова, содержащего/(например, /dev/sda1), это не сработает. Например, например:

var1=/dev/sda1
sed -i ":$var1:d" $file 

Я хотел бы пойти с решением, предложенным @Bolboa

Ответ 7

Используйте Perl, где переменные являются гражданами первого класса, а не просто расширяют макросы:

var=/Users/Documents/name/file perl -pe 's/\Q$ENV{var}/replace/g' $file
  • -p читает строку ввода построчно и печатает строку после обработки
  • \Q заключает в кавычки все метасимволы в следующей строке (не требуется для значения, представленного здесь, но необходимо, если значение содержало [ или некоторые другие значения, специальные для регулярных выражений)