Заменить строку в сценарии оболочки с помощью переменной

94

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

echo $LINE | sed -e 's/12345678/"$replace"/g'

но оно заменяется на $replaceвместо значения этой переменной.

Кто-нибудь может сказать, что пошло не так?

Виджай
источник
Для общего связанного с этим вопрос об обработке значений с косыми чертами в них, см stackoverflow.com/questions/5864146/use-slashes-in-sed-replace
tripleee

Ответы:

147

Если вы хотите интерпретировать $replace , вы не должны использовать одинарные кавычки, поскольку они предотвращают замену переменных.

Пытаться:

echo $LINE | sed -e "s/12345678/\"${replace}\"/g"

предполагая, что вы хотите вставить кавычки. Если вы не хотите, чтобы кавычки, используйте:

echo $LINE | sed -e "s/12345678/${replace}/g"

Расшифровка:

pax> export replace=987654321
pax> echo X123456789X | sed "s/123456789/${replace}/"
X987654321X
pax> _

Просто будьте осторожны и убедитесь, что в нем ${replace}нет значимых символов sed( /например, как), поскольку это вызовет путаницу, если не будет экранирован. Но если, как вы говорите, вы заменяете один номер другим, это не должно быть проблемой.

Paxdiablo
источник
Я не хочу, чтобы цитаты вставлялись. Я хочу, чтобы одно число было заменено другим,
Виджай,
1
paxdiablo: setтоже не нужен (и как вы собирались его использовать?). Просто replace=987654321.
Роман Чепляка
Я обычно всегда использую, exportчтобы гарантировать, что переменные установлены для детей, но, как вы говорите, вы можете легко избежать этого. Однако использование или отсутствие exportздесь не имеет значения (проблема стиля) и не влияет на фактический ответ, а именно, как использовать переменные в sedкоманде.
paxdiablo
Это решение, похоже, не работает с этой -iопцией. Знаете почему? или как заставить работать?
Габриэль
1
Также можно указать, что переключение с одинарных кавычек на двойные требует, чтобы любой $или `в sedскрипте был экранирован обратной косой чертой, чтобы защитить его от механизма замены оболочки для строк с двойными кавычками .
Tripleee
74

вы можете использовать оболочку (bash / ksh).

$ var="12345678abc"
$ replace="test"
$ echo ${var//12345678/$replace}
testabc
призрачная собака74
источник
3
Может, стоит упомянуть, что это специфично для bash (и ksh?). Вероятно , не импорт для большинства людей , но некоторые из нас все еще вынуждены работать на древней UNIXen :-)
paxdiablo
6
Остерегайтесь, это также не работает на dash, что есть /bin/shво многих современных Linux.
phihag 02
28

Не конкретно для вопроса, но для людей, которым нужна такая же функциональность, расширенная для ясности из предыдущих ответов:

# create some variables
str="someFileName.foo"
find=".foo"
replace=".bar"
# notice the the str isn't prefixed with $
#    this is just how this feature works :/
result=${str//$find/$replace}
echo $result    
# result is: someFileName.bar

str="someFileName.sally"
find=".foo"
replace=".bar"
result=${str//$find/$replace}
echo $result    
# result is: someFileName.sally because ".foo" was not found
боб
источник
8

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

echo $LINE | sed -e "s/12345678/$replace/g"
Дэйв
источник
4
echo $LINE | sed -e 's/12345678/'$replace'/g'

вы по-прежнему можете использовать одинарные кавычки, но вы должны «открывать» их, когда хотите, чтобы переменная развернулась в нужном месте. в противном случае строка воспринимается «буквально» (как правильно сказал @paxdiablo, его ответ также верен)

акира
источник
Это имеет проблему, заключающуюся в том, что использование $replaceвне кавычек заставит оболочку выполнять токенизацию пробелов и подстановочные знаки для значения. Будет казаться, что это работает с простыми значениями, но может резко взорваться на нетривиальных строках. Не используйте это в производственном коде.
Tripleee
2

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

sed -i "s#12345678#$replace#g" file.txt

Это сломается, если будут $replaceсодержать специальные sedсимволы ( #, \). Но вы можете предварительно $replaceпроцитировать их:

replace_quoted=$(printf '%s' "$replace" | sed 's/[#\]/\\\0/g')
sed -i "s#12345678#$replace_quoted#g" file.txt
Матье Мой
источник
0

У меня было аналогичное требование, но моя замена var содержала амперсанд. Избежание амперсанда, как это, решило мою проблему:

replace="salt & pepper"
echo "pass the salt" | sed "s/salt/${replace/&/\&}/g"
Ричард Солт
источник
-1

Используйте это вместо

echo $LINE | sed -e 's/12345678/$replace/g'

это работает для меня, просто удалите кавычки

Tunde Pizzle
источник
-2

Я предпочитаю использовать двойные кавычки, поскольку одиночные кавычки очень эффективны, поскольку мы использовали их, если не можем ничего изменить в них или можем вызвать замену переменной.

поэтому используйте двойные кавычки.

echo $LINE | sed -e "s/12345678/$replace/g"
SteveScm
источник
6
Это чем-то отличается от ответа Дэйва ?
devnull 03