Ответ 1
Используйте альтернативный разделитель регулярных выражений, так как sed
позволяет использовать любой разделитель (включая управляющие символы):
sed "s~$var~replace~g" $file
Как передать переменную, содержащую косую черту, как шаблон для sed
?
Например, если у меня есть следующая переменная:
var="/Users/Documents/name/file"
Я хочу передать его в sed
так:
sed "s/$var/replace/g" "$file"
Однако я получаю ошибки. Как я могу обойти проблему?
Используйте альтернативный разделитель регулярных выражений, так как sed
позволяет использовать любой разделитель (включая управляющие символы):
sed "s~$var~replace~g" $file
Чистый ответ bash: используйте расширение параметра для обратного слэша - сбрасывайте любые слэши в переменной:
var="/Users/Documents/name/file"
sed "s/${var//\//\\/}/replace/g" $file
Другой способ сделать это, хотя и более уродливым, чем ответ анубхавы, заключается в том, чтобы избежать всех обратных косых черт в var
с помощью другой команды sed
:
var=$(echo "$var" | sed 's/\//\\\//g')
тогда это будет работать:
sed "s/$var/replace/g" $file
Использование /
в sed в качестве разделителя будет конфликтовать с косой чертой в переменной при замещении, и в результате вы получите сообщение об ошибке. Один из способов обойти это - использовать другой разделитель, который уникален для любых символов, находящихся в этой переменной.
var="/Users/Documents/name/file"
вы можете использовать символ octothorpe, который подходит для случая (или любого другого символа, который не является /
для удобства использования)
sed "s#$var#replace#g"
или
sed 's#$'$var'#replace#g'
это подходит, когда переменная не содержит пробелов
или
sed 's#$"'$var'"#replace#g'
Разумно использовать вышеописанное, поскольку мы заинтересованы в замене того, что есть в этой переменной, только по сравнению с двойным цитированием всей команды, которая может заставить вашу оболочку интерпретировать любой символ, который может считаться специальным символом оболочки для оболочки.
Это старый вопрос, но ни один из ответов здесь не описывает операции, кроме 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
во-вторых.
Альтернативный разделитель работает только тогда, когда есть необходимость в поиске и замене. В таких случаях, когда необходимо удалить строки из файла на основе слова, содержащего/(например, /dev/sda1
), это не сработает. Например, например:
var1=/dev/sda1
sed -i ":$var1:d" $file
Я хотел бы пойти с решением, предложенным @Bolboa
Используйте Perl, где переменные являются гражданами первого класса, а не просто расширяют макросы:
var=/Users/Documents/name/file perl -pe 's/\Q$ENV{var}/replace/g' $file
-p
читает строку ввода построчно и печатает строку после обработки\Q
заключает в кавычки все метасимволы в следующей строке (не требуется для значения, представленного здесь, но необходимо, если значение содержало [
или некоторые другие значения, специальные для регулярных выражений)