Как заменить значение квадратными скобками, используя sed?
Мне нужно заменить переменные квадратными скобками в файле:
a=0
foo[1]=0
foo[2]=0
Я хочу заменить foo[1]=0
в foo[1]=2
,
Чтобы изменить значения a
Я использую:
func_update_value () {
field=$1
newvalue=$2
sed -i "s/^\($field=\).*/\1$newvalue/" file
}
field="a"
value="2"
func_update_value $field $value
но та же команда не работает для foo[x]
...
func_update_value () {
field=$1
newvalue=$2
sed -i "s/^\($field=\).*/\1$newvalue/" file
}
n=1
field="foo[$n]"
value="2"
func_update_value $field $value
Каков правильный синтаксис с sed
?
Изменение сделано функцией, возможно ли использовать один sed
команда для обоих случаев?
1 ответ
[1]
не является (т.е. не обязательно) литералом в оболочке. Тогда это не (то есть, конечно, нет) буквально как часть шаблона регулярного выражения в sed
,
Я проверил ваши предыдущие вопросы, и я думаю, что вы используете Bash. Первая часть моего ответа относится ко многим распространенным оболочкам, включая Bash (заметное исключение - zsh).
Возможная проблема в оболочке
Сначала вы назначаете значения переменным:
n=1
field="foo[$n]"
value="2"
Все это работает так, как вы ожидаете. Без кавычек 1
не является особенным, это не должно быть в кавычках. Цитируемый 2
может или не может быть процитировано, и это не будет иметь никакого значения. Двойные кавычки вокруг foo[$n]
Сделать разницу; хорошо, что они есть, вот так [
а также ]
ничего особенного и содержание field
переменная буквально foo[1]
наверняка.
Но тогда у вас есть
func_update_value $field $value
где $field
не котируется Сразу после расширения параметра строка
func_update_value foo[1] 2
и затем начинается сопоставление с объектами в вашем текущем каталоге (globbing), особенно:
[…]
Соответствует любому из вложенных символов.
Это означает, что если у вас есть файл или каталог с именем foo1
линия оценила бы
func_update_value foo1 2
Было бы еще хуже, если бы вы установили n=125
и у тебя было foo1
а также foo5
(И / или foo2
) в каталоге. Более одного файла будет соответствовать foo[125]
шаблон и окончательная форма линии будет как
func_update_value foo1 foo5 2
что, безусловно, не то, что вы хотите. Вы, вероятно, ничего не назвали foo1
в текущем каталоге, поэтому шаблон остается буквальным в этой точке и в строке
func_update_value foo[1] 2
управляет func_update_value
функция с буквальными аргументами foo[1]
а также 2
,
Если ваш код не выходит из строя на этом этапе, это только случайно foo1
в каталоге, а не из-за правильного кодирования. Правильное кодирование включает двойные кавычки всех переменных. Есть несколько редких сценариев, в которых вы не хотите цитировать, если знаете, что делаете; Это не один из них.
Также обратите внимание, что в самой функции есть field=$1
где $1
не котируется Проблема с кавычками $1
такой же, как и без кавычек $field
ранее.
Проблема в sed
Давайте предположим, что ваша функция правильно получила литерал foo[1]
аргумент и его местный field
переменная теперь содержит буквенную строку foo[1]
как это должно.
Проблема в [1]
как часть шаблона регулярного выражения в sed
не буквально. Как и в оболочке, он соответствует любому из вложенных символов (за исключением того, что сопоставляется с текстом, а не с именами файлов). foo[125]
будет соответствовать foo1
или же foo2
или же foo5
, foo[1]
Матчи foo1
только.
Делать sed
матч [
а также ]
буквально, вы должны избежать их в шаблоне. Вместо field="foo[$n]"
тебе нужно
field="foo\[$n\]"
Можно ли использовать один
sed
команда для обоих случаев?
Да. Ваша текущая команда похожа sed "s/^\($field=\).*/\1$newvalue/"
и это будет работать до тех пор, пока вы помните значение $field
будет интерпретироваться как часть шаблона (так [
, .
, \(
, $
и т. д. являются особенными) и ценность $newvalue
будет интерпретироваться как часть замены (например, \1
это особенное). И есть разделитель, который вы выбрали (/
), который не должен встречаться ни в одной из двух переменных, иначе он нарушит или изменит синтаксис.
Конечная нота
Только второе исправление (добавление обратной косой черты перед [
а также ]
) даже предотвратит расширение оболочки […]
Таким образом, это случайно "исправит" проблему цитирования в данном конкретном случае для данного конкретного значения переменной.
В целом, хотя вы должны применить оба исправления. И вам, безусловно, следует привыкнуть к цитированию переменных по умолчанию, это сэкономит ваше время и разочарование при отладке ваших будущих сценариев оболочки. Вот почему мой ответ не ограничивается вторым исправлением.