
Я сделал этот скрипт для курса. Он выполняет команды через ssh из аргументов скрипта, на нескольких удаленных серверах, указанных в файле:
#!/bin/bash
# The server file. Can be changed with the -f argument
SERVER_FILE='/vagrant/servers'
# The function to check if the chosen SERVER_FILE exists
filecheck() {
if [[ ! -e $SERVER_FILE ]]; then
echo "The file $SERVER_FILE does not exist." >&2
exit 1
fi
}
# The usage statement
usage() {
echo "usage $0 -vsn -f FILE 'COMMAND'"
echo " -v Verbose mode"
echo " -s Run command as sudo on remote server"
echo " -n Dry run, commands not actually executed"
echo " -f FILE Selects a different file other than /vagrant/servers"
exit 1
}
# The verbose mode text things
say() {
if [[ $VERBOSE = 'true' ]]; then
echo "$@"
fi
}
# The ssh command
sshing() {
ssh -o ConnectTimeout=2 $SERVER $@
}
# User executing the command should not be root
if [[ $UID -eq 0 ]]; then
echo "You should not execute this script with sudo or as root" >&2
echo "Use the -s argument if you want sudo powers" >&2
exit 1
fi
# DRYMODE is sshing by Default
DRYMODE='sshing'
#check to see if file SERVER_FILE exists
filecheck
# The options for the script
while getopts vsnf: OPTION; do
case $OPTION in
v)
echo "Verbose mode on"
VERBOSE='true'
;;
s)
say "Sudo mode"
SUDO='sudo'
;;
n)
say "Dry run mode"
DRYMODE='echo'
DRYRUN='DRY RUN: '
echo "DRY RUN MODE ON: "
echo
;;
f)
say "Different file mode"
SERVER_FILE=${OPTARG}
#check to see if file SERVER_FILE exists
filecheck
;;
*)
usage
;;
esac
done
echo
# shifts so that the options are removed from the list of arguments
shift $((OPTIND-1))
#Set a variable for the rest of the arguments, as a command
COMMAND="${@}"
# Checks if the user provided any arguments apart from the optinos
if [[ $# -eq 0 ]]; then
usage
exit 1
fi
# Executes the commands
for SERVER in $(cat ${SERVER_FILE}); do
say "Executing ${COMMAND} on ${SERVER}:"
$DRYMODE $DRYRUN $SUDO ${COMMAND} 2> /dev/null
CMDEX=$?
# if the exit status is 255, something is wrong with the server or is unreachable
if [[ $CMDEX -eq 255 ]]; then
echo "The server you're trying to reach does not exist or is unreachable. Aborting." >&2
exit 1
fi
# if the exit status is non 0 and non 255, something is wrong with the command
if [[ $CMDEX -ne 0 ]]; then
echo "Invalid command ${COMMAND} or wrong syntax. Aborting." >&2
exit 1
# if the exit status is non 0 and non 255, something is wrong with the command
fi
say "Command ${COMMAND} executed successfuly."
done
exit 0
И он отлично работает для простых команд (вроде ls
, ps
и даже adduser test
), но он просто ломается, если я даю ему любую команду, которая включает двойные кавычки, ЕСЛИ Я НЕ заключаю всю команду в одинарные кавычки.
Не знаю, ошибка ли это в моем коде или что-то еще, но я не могу передавать команды через него.
Итак, эта команда не работает:
[vagrant@admin01 vagrant]$ ./run-everywhere.sh -sv 'echo 1 | passwd --stdin test4'
Если я экранирую конвейер с помощью \|, он просто буквально записывает его как \|. Эта другая команда также не работает:
[vagrant@admin01 vagrant]$ ./run-everywhere.sh -sv 'echo "1" | sha256sum > file1'
РЕДАКТИРОВАТЬ:
Я обнаружил, что проблема с конвейером не работает: мне приходится писать sudo ПОСЛЕ конвейера, если команде нужны привилегии sudo. Это работает следующим образом:
[vagrant@admin01 vagrant]$ ./run-everywhere.sh -sv 'echo 1 | sudo passwd --stdin test4'
Но я все еще не могу перенаправить.
решение1
Попробуй это:
sshing () {
ssh -o ConnectTimeout=2 "$SERVER" "$@"
# ................................^..^ crucial quotes
}
# ...
cmd="$*"
# ...
while read -r SERVER; do
say "Executing ${COMMAND} on ${SERVER}:"
$DRYMODE $DRYRUN $SUDO sh -c "${COMMAND}" 2> /dev/null
# .....................11111.2..........2
# 1. run with a shell to enable redirections and pipe
# 2. crucial quotes
# ...
done < "$SERVER_FILE"
Запуск команды внутри оболочки с помощью sudo позволит всему конвейеру выполняться с повышенными правами.
Также вам следует избавиться от привычки использовать в именах переменных ВСЕ ЗАГЛАВНЫЕ БУКВЫ. Однажды вы случайно перезапишете PATH, а затем будете удивляться, почему ваш скрипт сломался.
решение2
Нашел проблему. Если я запускал скрипт с полномочиями sudo, чтобы самостоятельно коснуться некоторых файлов, он создавал файлы под именем и группой root, что означало, что у меня не было прав на этот файл.