Замініть рядок у сценарії оболонки, використовуючи змінну


93

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

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

але його замінюють $replaceзамість значення цієї змінної.

Хтось міг сказати, що пішло не так?


Для загального пов'язаного з цим питання про обробку значень з косими рисами в них, см stackoverflow.com/questions/5864146/use-slashes-in-sed-replace
tripleee

Відповіді:


146

Якщо ви хочете інтерпретувати $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(як, /наприклад,), оскільки це може викликати плутанину, якщо не вдасться уникнути. Але якщо, як ви говорите, ви замінюєте одне число іншим, це не повинно бути проблемою.


я не хочу, щоб котирування вводили. я хочу, щоб одне число замінили іншим
Віджай

1
paxdiablo: setтакож не є необхідним (і як ви все-таки збиралися ним користуватися?). Просто replace=987654321.
Роман Чепляка

Зазвичай я завжди використовую exportдля того, щоб встановити змінні для дітей, але, як ви кажете, ви можете так само легко уникнути цього. Однак використання або відсутність exportтут не має значення (проблема зі стилем) і не впливає на фактичну відповідь, тобто як використовувати змінні в sedкоманді.
paxdiablo

Здається, це рішення не працює з -iопцією. Чи знаєте ви чому? або як змусити це працювати?
Габріель

1
Можливо, також слід зазначити, що для переключення з одинарних на подвійні лапки потрібно, щоб у скрипті $або `в sedскрипті було використано зворотну скісну риску, щоб захистити його від механізму заміни оболонки на рядки з подвійними лапками .
триплі

73

ви можете використовувати оболонку (bash / ksh).

$ var="12345678abc"
$ replace="test"
$ echo ${var//12345678/$replace}
testabc

3
Можливо, хочеться згадати, що це специфічно для bash (і ksh?). Можливо, це не імпорт для більшості людей, але деякі з нас все ще змушені працювати на старовинних UNIXen :-)
paxdiablo

6
Обережно, це також не вдається на тире, як і /bin/shна багатьох сучасних Linux.
phihag

26

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

# 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за межами будь-яких лапок призведе до того, що оболонка виконає токенізацію пробілів та розширення символів підстановки для значення. Здається, це працює з простими значеннями, але може різко підірвати нетривіальні рядки. Не використовуйте це у виробничому коді.
триплеє

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'

це працює для мене, просто видаліть лапки


-2

Я вважаю за краще використовувати подвійні лапки, оскільки одинарні лапки дуже потужні, як ми їх використовували, якщо не можемо щось змінити всередині них або може викликати змінну заміну.

тому використовуйте встановлені подвійні лапки.

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

6
Чи це чимсь відрізняється від відповіді Дейва ?
devnull
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.