Я имею if
оператор, чтобы вычислить файлы и удалить все кроме последних трех файлов. Но я хочу выполнить эту команду удаленно. Как я могу объединиться ssh
с if
состояние?
Я попробовал это, но никакой успех.
#!/bin/bash
ssh -t test@192.168.94.139 "cd /var/www/test.com/backup ;
if [ $(ls | wc -l) -lt 3 ]
then
echo "Less"
else [ $(ls -t *.tgz|awk 'NR >3'|xargs rm -f) ]
echo "deleted"
fi"
Ошибка я добрался:
ls: не может получить доступ к *.tgz: Никакой такой файл или каталог
Примечание: существует на самом деле два слоя к вопросу здесь. Каждый, 'Я хочу выполнить нетривиальную задачу на удаленном сервере, доступном через SSH'. Другой, 'я пытаюсь передать сложную строку команде, и аргумент заканчивает тем, что отличался от того, что я предназначил'. Я отвечаю на вопрос низкого уровня, не обсуждая, является ли используемый подход "правильным" (удобный, неподверженный ошибкам, безопасный и т.д.) для решения высокого уровня один. Как обозначено другими ответами и комментариями, это вполне возможно не.
Ваша командная строка является главным образом правильной; только необходимо изменить заключение в кавычки немного.
Основная проблема состоит в том, что дважды заключенные в кавычки строки расширены Вашей локальной оболочкой, и таким образом, $(...)
части будут оценены в Вашей локальной системе. Для передавания их к удаленной системе необходимо включить сценарий в одинарные кавычки.
У Вас также есть некоторые встроенные кавычки. В Вашем исходном сценарии существуют аргументы в пользу двух echo
s; при изменении внешней цитаты на одинарные кавычки это будет awk сценарий. Эти effecitvely приводят к опускаемым кавычкам, который не беспокоится echo
s, но это испортит awk сценарий как большее - чем знак станет перенаправлением вывода. Таким образом после того, как Вы изменяете внешние кавычки на одинарные кавычки, изменяете кавычки к двойным кавычкам.
Это - Ваш сценарий с зафиксированным заключением в кавычки. Сценарий может иметь другие проблемы, я просто зафиксировал синтаксис.
#!/bin/bash
ssh -t test@192.168.94.139 'cd /var/www/test.com/backup ;
if [ $(ls | wc -l) -lt 3 ]
then
echo "Less"
else [ $(ls -t *.tgz|awk "NR >3"|xargs rm -f) ]
echo "deleted"
fi'
Да Вы можете exexute сложные сценарии через ssh
#!/bin/bash -e
ssh_cmd="$(cat <<-EOF
cd /var/www/test.com/backup;
if [ \$(ls | wc -l) -lt 3 ]; then
echo "less"
elif [ \$(ls -t *.tgz|awk 'NR >3'|xargs rm -f) ]; then
echo "deleted"
else
echo "something else"
fi
EOF
)"
ssh -t test@192.168.94.139 "$ssh_cmd"
Этот пример использует удар здесь документ для генерации командной строки. В любом случае, передающие сценарии через ssh подвержено ошибкам, потому что заключение в кавычки и выход переменных являются трудными (возражайте против обратной косой черты перед командами). Если сценарий становится слишком сложным, лучше скопировать его через scp
и затем выполните его на целевом узле.
Я не пытался исправить Ваш сценарий, но здесь являюсь примером о том, как подсчет и удаление на удаленном хосте могли работать:
#!/bin/bash -e
tmp_dir="$(mktemp -d)"
ssh_cmd="$(cat <<-EOF
cd "$tmp_dir"
cnt_tgz=(\$(find . -type f -name "*.tgz"))
if [[ \${#cnt_tgz[@]} -lt 3 ]]; then
echo "less"
else
rm "\${cnt_tgz[@]}"
echo "deleted"
fi
EOF
)"
touch "$tmp_dir/1.tgz"
ssh -t localhost "$ssh_cmd"
touch "$tmp_dir/2.tgz" "$tmp_dir/3.tgz"
ssh -t localhost "$ssh_cmd"
ls -t *.tgz
не будет работать, так как globbing только происходит в локальной системе. Также использование ls
для подсчета файлов не хорошая идея, так как он также возвращает записи как .
, ..
и каталоги.
Я думаю, что этот целый сложный материал заключения в кавычки является доказательством достаточно, чтобы не использовать его, но использовать сценарий вместо этого. Если Вы хотите избежать нескольких ssh
соединения, передайте сценарий по каналу к другому хосту и позвольте ему работать туда в одной команде:
Локальный файл, говорят myscript.sh
:
cd /var/www/test.com/backup;
if [ $(ls | wc -l) -lt 3 ]; then
echo "less"
elif [ $(ls -t *.tgz|awk 'NR >3'|xargs rm -f) ]; then
echo "deleted"
else
echo "something else"
fi
Затем:
cat myscript.sh | \
ssh -t test@192.168.94.139 \
"cat - > /tmp/ms.sh && sh /tmp/ms.sh && rm /tmp/ms.sh"
Или (предотвращение бесполезного использования кошки):
ssh -t test@192.168.94.139 \
"cat - > /tmp/ms.sh && sh /tmp/ms.sh && rm /tmp/ms.sh" \
< myscript.sh
Это передает локальный сценарий по каналу myscript.sh
удаленной стороне, где это перенаправляется во (временный) файл /tmp/ms.sh
, выполняемый, и наконец удаленный.
Примечание: Я не проверял исходный сценарий на наличие ошибок, но просто требуемый для показа идеи. Никакое подверженное ошибкам заключение в кавычки не необходимо, и все команды в сценарии выполняются на удаленной стороне.
Я предпочел бы помещать сценарий в удаленный экземпляр и просто выполнять его через ssh, но здесь являюсь своим предложением, как это могло быть сделано в способе, которым Вы хотите:
#!/bin/bash
HOST='test@192.168.94.139'
REMOTE_PATH='/var/www/test.com/backup'
COMMAND1="ssh \"$HOST\" 'ls \"$REMOTE_PATH\" | wc -l'"
COMMAND2="ssh \"$HOST\" 'ls -t \"$REMOTE_PATH\"/*.tgz'"
COMMAND3="xargs ssh \"$HOST\" rm -rf"
if [[ $(eval "$COMMAND1") -le 3 ]]
then
echo "Less"
else
eval "$COMMAND2" | awk 'NR > 3' | eval "$COMMAND3" && echo "Deleted"
fi
Примечания:
-lt
заменяется -le
.eval
- создайте команду путем конкатенации аргументов.\"
в $COMMAND{1..3}
выражение, но я решаю добавить их.