В ответах на:
I want to write the whole output to the file, a copy of the original with the changes made.
Вы можете либо перенаправить на файл, например
sed '4{ s/fox/elephant/; s/dog/cat/}' infile > modified_file
Или изменить в -место с флагом -i
:
sed -i '4{ s/fox/elephant/; s/dog/cat/}' infile
... или сделайте резервную копию исходного файла и запишите изменения с тем же именем исходного файла.
sed -i.backup '4{ s/fox/elephant/; s/dog/cat/}' infile
Или командой w
:
sed '4{ s/fox/elephant/; s/dog/cat/ }; w modified_file' infile
Если вы хотите написать только те строки, что s
подстановка команд прошла успешно (, а это не то, о чем вы просите в настоящее время ), с помощью флага w
вы можете сделать:
sed '4{ s/fox/elephant/; s/dog/cat/w modified_file
}' infile
ssh
не запускает команду на удаленном хосте, но отправляет код для интерпретации оболочки входа удаленного пользователя, поэтому, если вы хотите, чтобы эта удаленная оболочка выполняла данную команду с заданным списком аргументов, вам нужно создать командную строку в этом синтаксисе оболочки, которая заставит эту оболочку выполнить эту команду с этими аргументами.
Оболочка — это интерпретатор командной строки. Его основная цель состоит в том, чтобы выполнять команды с учетом командных строк (командные строки, которые являются другим способом сказать код в синтаксисе оболочки ), который вы ему даете. В оболочке Korn -, подобной вашей, со значением $FILENAME
, равным File Name With Spaces.mp4
, и командной строкой типа:
ssh server md5sum filelocation/"${FILENAME}"
Задача оболочки состоит в том, чтобы выполнить найденный в $PATH
файл с именемssh
(что-то вроде/usr/bin/ssh
)с этими аргументами:
argv[0]
:ssh
argv[1]
:server
argv[2]
:md5sum
argv[3]
:filelocation/File Name With Spaces.mp4
В синтаксисе языка оболочки аргументы команды разделяются пробелом, $xxx
запускает раскрытие параметра, а кавычки здесь используются для предотвращения разделения и подстановки при таком расширении.
Затем задача ssh
состоит в том, чтобы из полученного списка аргументов соединиться с server
, соединить оставшиеся аргументы пробелами,и передать результат в оболочку входа удаленного пользователя (их предпочтительную оболочку, которую они могут изменить с помощью chsh
, zsh
для меня, но может быть tcsh
, fish
, yash
, bash
, rc
... ), выполнив его с аргументами:
argv[0]
:имя этой оболочки argv[1]
:-c
argv[2]
:что -результат, так вот:md5sum filelocation/File Name With Spaces.mp4
Здесь, несмотря на то, что все оболочки имеют разный синтаксис, эта командная строка достаточно проста, чтобы большинство интерпретировало ее одинаково. То есть он выполнит команду /path/to/md5sum
с этими аргументами:
argv[0]
:md5sum
argv[1]
:filelocation/File
argv[2]
:Name
argv[3]
:With
argv[4]
:Spaces.mp4
Чтобы команда md5sum
запускалась с одним аргументом filelocation/File Name With Spaces.mp4
, нам нужно сообщить этой удаленной оболочке, что эти пробелы не следует использовать в качестве разделителей аргументов. И это делается с помощью цитирования/экранирования. И синтаксис цитирования значительно различается между оболочками.
В любом случае пробел — не единственный символ, который может вызвать проблемы. Любой символ, являющийся специальным в синтаксисе удаленной оболочки, также будет проблемой. Например, если бы имя файла было $(reboot).mp4
или blah;rm -rf ~;blah.mp4
, у вас были бы большие проблемы.
Если вы знаете, что удаленная оболочка похожа на -Борна, вы можете сделать:
#! /bin/zsh -
while IFS=, read -ru3 location user md5 file rest; do
md5sum -- $file | read check rest
filename=$file:t
print -r -- $filename
ssh -n server "md5sum filelocation/${(qq)filename}" | read remotecheck rest
if [[ $md5 = $check ]]; then
printf '%s File MD5: %s\n' Local "$check" Remote "$remotecheck"
fi
done 3< $path_to_file
Это ${(qq)file}
кавычки с одинарными кавычками, что является самым безопасным способом заключать в кавычки такие вещи в Bourne -, как оболочки . Так что в вашем случае File Name With Spaces.mp4
будет передано как 'File Name With Spaces.mp4'
. Если бы это было File Name With Quote's.mp4
, это было бы 'File Name With Quote'\''s.mp4'
, где все цитируется с '...'
, кроме самого '
, которое цитируется с \
.
Если вы не можете гарантировать, что удаленная оболочка будет похожа на -Борна, см. Как выполнить произвольную простую команду через ssh, не зная оболочки входа удаленного пользователя? для получения дополнительных опций.
Здесь, для вашего конкретного случая использования -, чтобы сравнить локальную и удаленную контрольные суммы,другой вариант - использовать режим проверки md5sum
(с-c
):
#! /bin/zsh -
while IFS=, read -ru3 location user md5 file rest; do
(cd -P -- $file:h && md5sum -- $file:t) |
ssh -n server 'cd./filelocation && md5sum -c'
done 3< $path_to_file
На этот раз имя файла записывается локальным md5sum
и читается удаленным на его стандартном вводе, поэтому нам не нужно заключать его в кавычки для удаленной оболочки. И эта командная строка cd./filelocation && md5sum -c
понимается большинством оболочек (префикс ./
предназначен для того, чтобы избежать эффекта $cdpath
/ $CDPATH
в csh/tcsh/bash, оболочках, которые делают или могут читать свой файл rc при вызове не -в интерактивном режиме или через ssh ).
Проблема заключается в этой строке и в том, как ее интерпретируют две оболочки.
REMOTECHECK=$(ssh server md5sum filelocation/"${FILENAME}" < /dev/null | awk '{ print $1 }')
Давайте предположим, что имя файла "счастливый понедельник", и мы рассмотрим конкретно команду ssh
После оценки значения переменной локальная оболочка увидит это
ssh server md5sum 'filelocation/happy monday' < /dev/null
В частности, кавычки удаляются, и оболочка обрабатывает содержимое как одно слово, filelocation/happy monday
.
Результат теперь выполняется ssh
и аргументы командной строки передаются в удаленную оболочку (независимо от того, что это может быть ). Помните, что кавычки были удалены, так что это то, что выполняется удаленно:
md5sum расположение файла/счастливого понедельника
На данный момент md5sum
ищет два файла, filelocation/happy
и monday
.
Для предотвращения потери кавычек необходимо заключить всю команду в другой набор
ssh server "md5sum 'filelocation/happy monday'"
Повторное применение этого к исходному коду,
REMOTECHECK=$(ssh -n server "md5sum 'filelocation/$FILENAME'" | awk '{ print $1 }')