#!/bin/bash
set -- {A..O}
j=0
for i
do j=$((j+1))
mkdir "Dir$j"
touch "Dir$j/$i"
done
Этот код использует позиционные аргументы для выполнения своей работы, поэтому они стираются (ничего важного, но полезно знать).
Ваш сценарий в том виде, в котором он написан , будет продолжать выполнять все ваши удаленные команды одновременно, но при использовании вами wait
явно будет ожидать завершения фоновой задачи. В случае, когда вы описываете высоконагруженный сервер -, это означает, что ваша команда ssh
не истекает по тайм-ауту, а просто занимает много времени для завершения, поэтому скрипт делает именно то, что вы просите. ConnectTimeout
спорный, когда вы можете успешно установить соединение ssh
.
Если вы хотите использовать такой сценарий, а не инструмент, предназначенный для распределенного удаленного выполнения, такой как Ansible , я могу изменить ваш сценарий следующим образом:
exec_ssh() {
while read file; do
if ! ssh -q -o BatchMode=yes -o ConnectTimeout=2 "$i" "$command" 2>>/dev/null & then
echo "$i is not reachable via non-interactive SSH or remote command threw error - exit code $?" >> /tmp/not_reachable
fi
done < "$file" > /tmp/output.csv &
}
run_command() {
export -f exec_ssh
export command
nohup bash -c exec_ssh &>> "$log_file" &
}
Также, возможно, стоит рассмотреть вопрос о разделении теста «Могу ли я подключиться к хосту по SSH» и теста «Могу ли я выполнить задание»:
if ssh -q -o BatchMode=yes -o ConnectTimeout=2 "$host" true; then
# connection succeeded
if ! ssh -q -o BatchMode=yes -o ConnectTimeout=2 "$host" "$command" & then
echo "Remote command threw $?"
fi
else
echo "SSH threw $?"
fi
По мере того, как ваши локальные и удаленные команды становятся все более сложными, вы быстро перегрузитесь попытками втиснуть все это в один согласованный сценарий, а с сотнями или тысячами фоновых процессов вы, вероятно, столкнетесь с проблемами конфликтов ресурсов даже с мощной локальной машиной.
Вы можете взять это под контроль с помощью xargs -P
. Я обычно разбиваю такие задачи на два сценария.
Как правило, этот сценарий имеет единственный аргумент, который является именем хоста, и выполняет все необходимые проверки, предварительные -задачи, ведение журнала и т. д. Например,:
#!/bin/bash
hostname=$1
# simple
cat remote.sh | ssh user@$hostname
# sudo the whole thing
cat remote.sh | ssh user@$hostname sudo
# log to files
cat remote.sh | ssh user@$hostname &> logs/$hostname.log
# or log to stdout with the hostname prefixed
cat remote.sh | ssh user@$hostname 2>&1 | sed "s/^/$hostname:/"
Скрипт, который вы хотите запустить удаленно, но теперь вам не нужно впихивать его в кавычки -лайнера и разбираться с кавычками -, спасаясь от ада.
cat host_list.txt | xargs -P 16 -n 1 -I {} bash local.sh {}
Где:
-P 16
разветвит до 16 подпроцессов --n 1
передает ровно один аргумент на команду -I {}
заменит аргумент вместо {}
[здесь это не обязательно, но может быть полезно для создания более сложных вызовов xargs. Таким образом, даже если один из ваших локальных или удаленных сценариев зависнет, остальные 15 будут работать беспрепятственно.