Как да изпълня отдалечена команда през 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 в homedir на 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, но потенциалът някой да изпълнява произволен отдалечен код чрез mycommand '$(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 Cloud. Сценарият е, че някаква машина, която стартира от автоматично мащабиране, трябва да извърши някакво действие на друг сървър, предавайки новосъздадения 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