![Удаленный запуск нескольких команд с помощью скрипта bash](https://rvso.com/image/191769/%D0%A3%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9%20%D0%B7%D0%B0%D0%BF%D1%83%D1%81%D0%BA%20%D0%BD%D0%B5%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%D0%BA%D0%B8%D1%85%20%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%20%D1%81%20%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%D1%8C%D1%8E%20%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%B0%20bash.png)
Мне нужно войти на удаленные серверы через ssh и перейти в папку tmp, а там запустить команду rm. Но когда я запускаю скрипт ниже, он переходит на удаленный сервер, но не переходит в папку temp и не запускает команду rm.
#!/bin/bash
for i in `cat list`
echo $server
echo "------------------------------------------"
ssh $server << MYCOMMANDS
cd /tmp
rm log52.log
MYCOMMANDS
решение1
Единственная реальная проблема с вашим кодом заключается в том, что в вашем цикле отсутствуют do
и done
, что приведет к синтаксическим ошибкам, а также в том, что вы используете i
в качестве переменной цикла , но пытаетесь соединиться с какой-то server
переменной, которая вполне может быть неустановленной.
Кроме того, вы используете cat
в команде подстановку без кавычек, котораяв целомплохая идея, если вы не знаете наверняка, что будете читать строки без пробелов и символов подстановки имен файлов (хотя большинство имен хостов ведут себя в этом отношении хорошо).
В большинстве случаев лучше читать входные данные построчно, например так:
while IFS= read -r remote; do
ssh -n "$remote" 'rm -f /tmp/log52.log'
done <list
Я использую ssh -n
здесь, чтобы остановить ssh
чтение его стандартного входного потока (который был бы подключен к list
файлу). Без -n
, ssh
будет прочитано оставшееся содержимое list
и ваш цикл будет выполнять только одну итерацию.
В качестве альтернативы, если вы действительно хотите прочитать команды из документа here-document:
while IFS= read -r remote; do
ssh -T "$remote" <<'END'
rm -f /tmp/log52.log
END
done <list
Здесь я использую ssh -T
для явного отключения выделения псевдотерминала, что не нужно, поскольку мы не делаем ничего, что требует взаимодействия с пользователем. Я делаю это, поскольку ssh
заметит, что его стандартный поток ввода содержит данные, поэтому он предупредит нас об отсутствии функционирующего терминала на удаленной системе для выполнения интерактивных действий. Здесь нам не нужно -n
with ssh
, поскольку мы переназначаем стандартный поток ввода для ssh
from here-document.
Но цикл можно заменить одной командой
xargs -I {} ssh {} 'rm -f /tmp/log52.log' <list
... где xargs
утилита будет читатьлиниииз файла list
, замените {}
в ssh
команде строку, считанную из файла, и выполните действие доступа к удаленным системам для удаления определенного файла. Я использую, rm -f
чтобы не вызывать ошибку, если нет файла для удаления.
Некоторые реализации xargs
позволяют выполнять утилиту параллельно, например, с помощью -P 4
(что позволит ssh
одновременно выполнять не более четырех команд).
решение2
#! /bin/bash
for i in `cat list`
do
echo $i
echo "-------------------------"
ssh $i "rm /tmp/log52.log"
done
Если вам нужно удалить только один файл, вы можете просто указать это в одной строке. Кроме того, вам может быть полезно добавить -f
в rm
.
решение3
Вы не можете просто перенаправить stdin сеанса ssh таким образом. Вы должны увидеть сообщение об ошибке, похожее на:
Псевдотерминал не будет выделен, поскольку stdin не является терминалом
Вам нужно использовать опцию -tt для ssh, чтобы принудительно выделить псевдотерминал. Попробуйте это:
#!/bin/bash
for i in `cat list`
echo $server
echo "------------------------------------------"
ssh -tt $server << MYCOMMANDS
cd /tmp
rm log52.log
MYCOMMANDS