В этом «объявлении» упоминается версия 6.3, поэтому оно выглядит подлинным.
Не уверен, что это будет более читабельно для вас, но вы можете построить выражение sed
сначала с помощью printf
, а затем использовать его сsed
:
sed_expr=$(printf 's/$to = ".*";$/$to = "%s";/' "$new_email_address")
sed -i "$sed_expr" FILE
Таким образом, ИМО, легче увидеть, что sed будет делать в целом, а также какую роль в нем будет играть ввод.
Здесь я бы использовал perl
. -i
— это нестандартная опция -, которую некоторые реализации sed
скопировали из perl
, но она не переносима. Использование sed
таким образом также является уязвимостью для внедрения команд, поскольку содержимое $new_email_address
в конечном итоге интерпретируется как sed
код (, а в языке GNU sed
есть команды, которые могут запускать произвольные команды, попробуйте экземпляр, вводящий /;ereboot;#
в этом приглашении read
).
IFS= read -r new_email_address
REPLACEMENT="$new_email_address" perl -pi -e '
s{
(\$to \s* = \s* ").* (" \s* ; \s* )$
}{$1$ENV{REPLACEMENT}$2}gx
' FILE
Вperl
s{...}{...}flags
в дополнение к s/.../.../flags
, что упрощает просмотр совпадающих пар (и позволяет {
, }
внутри, если они совпадают ). x
, вы можете добавить пробелы (и даже комментарии )внутри регулярного выражения, чтобы его было легче читать (обратите внимание, что эти пробелы не являются частью регулярного выражения, это \s*
] соответствует любому количеству пробелов ). &
, /
,обратную косую черту или новую строку, передав их, например, через переменную среды. -C
/ -Mlocale
/ -Mopen=locale
..., perl
работает на уровне байтов, поэтому его .*
всегда будет соответствовать, даже если ввод не не формирует допустимый текст в локали. sed
реализаций, perl
не имеет ограничения на длину строки (, кроме доступной памяти ), и не будет подавляться при вводе, содержащем байты NUL или не заканчивающемся символом новой строки. Чтобы разрешить пробелы и в замещающей части, вы можете добавить флаг e
, который приводит к замене кода perl
:
REPLACEMENT="$new_email_address" perl -pi -e '
s{
(\$to \s* = \s* ").* (" \s* ; \s* )$
}{
$1. $ENV{REPLACEMENT}. $2
}gxe
' FILE
Например. Также помните, что использование read
без установки $IFS
и без -r
редко имеет смысл.
Один из способов разделить кавычки состоит в том, чтобы разорвать команду sed, воспользовавшись помощью нескольких -кодлеток sed для поиска и замены.
q=\"; # a double quote character
sed -i \
-e '/$to = ".*";$/c\' \
-e "\$to = $q$new_email_address$q;" \
FILE
sed -i \
-e '/$to = ".*";$/!b' \
-e "s//\$to = $q$new_email_address$q;/" \
FILE;
Цитируемая команда чем-то похожа на то, что я написал в недавнем ответе(с добавлением -i
):
sed 's/$to = ".*";$/$to = "'"$new_email_address"'";/' file
Это вызов sed
с помощью одной команды редактирования. Команда, используемая в выражении sed
, — это команда s
, которая выполняет подстановку, то есть заменяет что-то, что соответствует регулярному выражению, чем-то другим.
Общая форма команды s
— range s/pattern/replacement/flags
. В команде, с которой мы здесь имеем дело, нет range
выражения (, команда s
применяется ко всем строкам во входном тексте ), и нет flags
. Таким образом, у нас есть sed
сценарий редактирования общей формы
s/pattern/replacement/
Как видно из команды, бит pattern
равен
$to = ".*";$
Этот шаблон соответствует буквальному тексту $to = "
, за которым следует что угодно(любая длина последовательности любого символа ), за которой следует буквальный текст ";
. $
в конце заставляет последний бит ";
соответствовать самому концу строки.
Затем у нас есть бит replacement
.
Так как вы хотите заменить что-то, что зависит от значения переменной оболочки, мы должны временно выйти из одиночной строки -в кавычках, которая является выражением sed
. Мы делаем это сразу после
$to = "
на замену. Значение переменной оболочки new_email_address
вставляется, должным образом заключенное в двойные кавычки, чтобы оболочка не разбивала его на пробелы и не выполняла подстановку имени файла для его значения.
После вставки значения мы заканчиваем часть replacement
команды s
на
";
и это полное поле replacement
,$to = "
, за которым следует некоторое значение (, новый адрес электронной почты ), а затем ";
.
Итак, чтобы разбить его на части и сделать очевидным, что каждый бит этой команды делает и:
Структура команды sed
:
sed 's/$to = ".*";$/$to = "'"$new_email_address"'";/' file
s/ pattern / replacement /
Биты строк, составляющих выражение sed
в оболочке:
sed 's/$to = ".*";$/$to = "'"$new_email_address"'";/' file
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^
single-quoted string double-quoted final single-quoted bit
string for shell
variable expansion
Вышеизложенное в более схематичном виде
sed 'something here'"$variable_value_here"'ending here' file
Бит something here
заканчивается двойной кавычкой, а бит ending here
начинается двойной кавычкой.
Еще один способ может быть:
email_rhs=$(printf '%s\n' "$new_email_address" | sed -e 's:[\&/]:\\&:g;$!s:$:\\:')
sed -i -Ef - <<_CODE_ FILE_PATH
$(printf -v fmt \
'
s/
(\$to \s* = \s*) ".*" ;$
/
\\\\1 "%%s" ;
/g
'
printf "${fmt//[$IFS]/}" "$email_rhs")
_CODE_