Re: ошибка 23 - Наиболее частая причина появления этой ошибки - допустить небольшую опечатку в исходном коде rsync. Просмотрите свою исходную команду и убедитесь, что все проверено на ls, и поищите глупые тонкие вещи, такие как лишнее пространство или 1-литровую проблему.
В то время как:
sed "0,\~$var~s~$var~replacement~"
Может использоваться для изменения разделителя регулярных выражений, встраивание расширений переменных в код sed
(или любой другой интерпретатор) в общем случае очень неразумно.
Во-первых, здесь ограничитель - не единственный символ, который нужно экранировать. Это также необходимо для всех операторов регулярных выражений.
Но что более важно, особенно с GNU sed
, это уязвимость, связанная с внедрением команд. Если содержимое $ var
не находится под вашим контролем, это так же плохо, как передача произвольных данных в eval
.
Попробуйте, например:
$ var='^~s/.*/uname/e;#'
$ echo | sed "0,\~$var~s~$var~replacement~"
Linux
Была запущена команда uname
, к счастью, безобидная ... на этот раз.
Реализации, отличные от GNU sed
, не могут запускать произвольные команды, но могут перезаписывать любой файл (с помощью команды w
), что практически так же плохо.
Более правильный способ - экранировать проблемные символы в $ var
сначала :
NL='
'
case $var in
(*"$NL"*)
echo >&2 "Sorry, can't handle variables with newline characters"
exit 1
esac
escaped_var=$(printf '%s\n' "$var" | sed 's:[][\/.^$*]:\\&:g')
# and then:
sed "0,/$escaped_var/s/$escaped_var/replacement/" < file
Другой подход - использовать perl
:
var=$var perl -pe 's/\Q$ENV{var}\E/replacement/g && $n++ unless $n' < file
Примечание что мы не расширяем содержимое $ var
внутри кода, переданного в perl
(что может быть еще одной уязвимостью внедрения команд), но разрешаем perl
расширяться его содержимое как часть обработки регулярного выражения (и в пределах \ Q ... \ E
, что означает, что операторы регулярного выражения не обрабатываются специально).
Если $ var
содержит символы новой строки, они могут совпадать только в том случае, если в конце есть только один.В качестве альтернативы можно передать параметр -0777
, чтобы ввод обрабатывался как отдельная запись, а не построчно.
Подобно решению Стефана perl
, awk
может избежать проблемы защиты "опасного" интерполированного значения с помощью альтернативного подхода:
export pattern="anypattern" # or whatever shell quoting is needed
awk 'NR==1,$0~ENVIRON["pattern"] {sub(ENVIRON["pattern"],"replacement")} 1' input
# or gsub if you want multiple matches on the first line with any match
и если данные (возможно) большие, а шаблон (возможно) дорогой, awk
также может избежать ненужного сопоставления после нахождения одного совпадения с помощью несколько иной идиомы:
awk '!x&&$0~ENVIRON["pattern"] {sub(ENVIRON["pattern"],"replacement");x=1} 1' input
# ditto
Напоминание: awk
(или sed
) специально обрабатывает &
в значении замены; если вам нужен фактический &
префикс с \
(который обычно должен быть сначала закавычен; здесь это ''
) и аналогично удвоить фактический \