Как выполнить удаленную команду по ssh с аргументами?

В моем .bashrc я определяю функцию, которую я могу использовать в командной строке позже:

function mycommand() {
    ssh [email protected] cd testdir;./test.sh "$1"
}

При использовании этой команды на удаленном хосте выполняется только команда cd; команда test.sh выполняется на локальном хосте. Это связано с тем, что точка с запятой разделяет две разные команды: команду ssh и команду test.sh.

Я попытался определить функцию следующим образом (обратите внимание на одинарные кавычки):

function mycommand() {
    ssh [email protected] 'cd testdir;./test.sh "$1"'
}

Я попытался сохранить команду cd и команду test.sh вместе, но аргумент $1 не разрешается независимо от того, что я передаю функции. Всегда пытаются выполнить команду

./test.sh $1

на удаленном хосте.

Как правильно определить mycommand, чтобы сценарий test.sh выполнялся на удаленном хосте после перехода в каталог testdir с возможностью передачи аргумента, заданного mycommand, в test.sh?


person Alex    schedule 29.08.2013    source источник
comment
Это не имеет отношения к главному, но вы можете использовать && вместо точки с запятой для объединения команд, выполняемых на удаленном хосте: cd testdir && ./test.sh "$1". При такой форме (из-за короткого замыкания при оценке && в bash) в случае сбоя cd вторая команда не будет выполнена, и вы не сможете непреднамеренно запустить другую test.sh в домашнем каталоге user.   -  person Alp    schedule 29.08.2013


Ответы (4)


Вместо этого сделайте это так:

function mycommand {
    ssh [email protected] "cd testdir;./test.sh \"$1\""
}

Вам по-прежнему нужно передать всю команду в виде одной строки, но в этой единственной строке вам нужно расширить $1, прежде чем она будет отправлена ​​​​в ssh, поэтому вам нужно использовать для нее "".

Обновлять

Другой правильный способ сделать это на самом деле - использовать printf %q для правильного цитирования аргумента. Это сделало бы аргумент безопасным для анализа, даже если он содержит пробелы, одинарные кавычки, двойные кавычки или любой другой символ, который может иметь особое значение для оболочки:

function mycommand {
    printf -v __ %q "$1"
    ssh [email protected] "cd testdir;./test.sh $__"
}
  • При объявлении функции с function () не требуется.
  • Не комментируйте это только потому, что вы POSIXist.
person konsolebox    schedule 29.08.2013
comment
@JoSo Да, это основа, поэтому в зависимости от использования пользователь может выбрать санацию аргумента, который ему нужен. Что касается базового ssh, вероятно, нет лучшего способа - если вы сначала не выполняете передачу файлов и т. д. - person konsolebox; 26.06.2014
comment
@JoSo Да, лучшим подходом было бы определить функцию кавычек, например quote() { printf "'%q'" "$1"; }, а затем выполнить ssh user@host "cd testdir; ./test.sh $(quote "$1")" - person augurar; 05.08.2014
comment
@augurar, почти, но %q результаты цитируются сами по себе; окружение их буквальными кавычками не является необходимым или правильным. printf -v arg_str '%q ' "$1"; ssh user@host "cd testdir; ./test.sh $arg_str" достаточно. - person Charles Duffy; 16.05.2016
comment
@CharlesDuffy Зачем вам нужно добавлять пробел? - person konsolebox; 17.05.2016
comment
@konsolebox, только для непосредственного случая, на самом деле нет, но таким образом идиома масштабируется, если добавляется больше аргументов, а не смешивает их все вместе. - person Charles Duffy; 17.05.2016
comment
@CharlesDuffy Хороший улов, это опечатка. Должно быть printf "%q" "$1". - person augurar; 18.05.2016

Я использую следующее для выполнения команд на удаленном компьютере с моего локального компьютера:

ssh -i ~/.ssh/$GIT_PRIVKEY user@$IP "bash -s" < localpath/script.sh $arg1 $arg2
person muratgozel    schedule 30.12.2018

Возрождение старой темы, но этот довольно чистый подход не был указан.

function mycommand() {
    ssh [email protected] <<+
    cd testdir;./test.sh "$1"
+
}
person Ted Bigham    schedule 11.12.2014
comment
Это не удастся, если $1 расширится до строки, содержащей " и расширяемые символы, такие как $ и `. - person konsolebox; 19.01.2015
comment
Это не терпит неудачу. Это имеет тот же эффект, что и выполнение любой команды, отличной от ssh, с аргументами. ОП не просил урок двойного уклонения от аргументов. Только как заставить его вторую команду выполнить тот [какой-либо] аргумент, который он уже имел в виду. - person Ted Bigham; 19.01.2015
comment
Если пользователь спрашивает, как выполнить что-то через ssh, разумно ожидать, что любой ответ будет охватывать предостережения, характерные для ssh (т. е. которые не существуют при локальном запуске кода). Двойное расширение (и уязвимости внедрения оболочки, вызванные тем же самым) являются одними из таких предостережений, которые не существовали бы с cd testdir; ./test.sh "$1", запускаемым непосредственно в локальной оболочке, но существуют с исходным кодом. - person Charles Duffy; 18.05.2016
comment
Я не думаю, что вы проголосовали бы за ответ на вопрос о базе данных, который продемонстрировал практику с уязвимостями SQL-инъекций, но потенциал того, что кто-то запускает произвольный удаленный код через mycommand '$(rm -rf ~)', ничуть не менее серьезен. - person Charles Duffy; 18.05.2016
comment
(... и дело в том, что изменения, необходимые для обеспечения безопасности вашего кода, довольно малы: printf -v argv_str '%q ' "$@"; ssh user@host "bash -s $argv_str" <<'+', а остальное может остаться как есть; цитирование сигилы + для heredoc предотвращает его расширение). - person Charles Duffy; 18.05.2016
comment
@CharlesDuffy, но вероятность того, что кто-то запустит произвольный удаленный код с помощью моей команды '$ (rm -rf ~)', ничуть не менее серьезна. -› Не вижу в этом смысла. Есть отличия: ошибочное или неожиданное расширение против явной команды. Вы не говорите, что они представляют одинаковую опасность только потому, что они оба представляют опасность. Есть степени или уровни. - person konsolebox; 20.05.2016
comment
@konsolebox, если я запустил for file in /data/**; do ./mycommand "$file"; done, я только что явно запустил команду, потому что файл в каталоге data имел вредоносное имя? Частично смысл разделения кода и данных (то есть предотвращения непреднамеренного анализа последних как первых) заключается в том, что код должен оставаться полностью под проверенным человеческим контролем, но данные часто поступают из ненадежных источников. - person Charles Duffy; 28.11.2016
comment
@konsolebox, ... да, простота использования действительно различается, но это не оправдание тому, что что-то может быть известно для использования, когда вместо этого оно может быть полностью безопасным (отсутствие какой-либо пока еще полностью неизвестной уязвимости). - person Charles Duffy; 28.11.2016

Это пример, который работает в облаке AWS. Сценарий заключается в том, что какой-то машине, которая загрузилась с автомасштабирования, необходимо выполнить какое-то действие на другом сервере, передав только что созданный экземпляр DNS через SSH.

# Get the public DNS of the current machine (AWS specific)
MY_DNS=`curl -s http://169.254.169.254/latest/meta-data/public-hostname`


ssh \
    -o StrictHostKeyChecking=no \
    -i ~/.ssh/id_rsa \
    [email protected] \
<< EOF
cd ~/
echo "Hey I was just SSHed by ${MY_DNS}"
run_other_commands
# Newline is important before final EOF!

EOF
person Cyril Duchon-Doris    schedule 14.03.2018