
У меня есть простой скрипт, который выполняет команды на удаленном хосте, используя ssh
here-document.
Я пытался сделать это с помощью однострочного командного файла, но не мог понять, как сделать here-document вне скрипта. Возможно ли это? Я потратил некоторое время на гугление и чтение документации о here-documents, но ничего не получалось.
Этот скрипт работает отлично — мне нужен был раздел here-document для awk
удаленного запуска через ssh, но я обычно предпочитаю писать однострочники для простых вещей:
#!/bin/bash
# it looks up all my hosts with 'db' in the name
# then gets the PID of any rsyncs running as user 'research'
# and pumps them into xargs
getHosts=(`curl --silent "http://assetts.lab/all_hosts" | grep -v ^# | awk -F" " '{print$1}'|grep db`)
for BOX in ${getHosts[@]};do
echo "$BOX: "
ssh -T sshUser@$BOX <<"EOF"
ps -ef | egrep "rsync|iasync" | awk -F" " '{if ($1 ~ "research") print $2}'|sudo xargs -i ps -fp '{}'
#ps -ef | egrep "rsync|iasync" | awk -F" " '{if ($1 ~ "research") print $2}'|sudo xargs -i kill '{}'
EOF
echo
done
Я, наверное, упускаю что-то простое... В любом случае, спасибо за любые предложения :)
решение1
Я не вижу необходимости что-либо делать с использованием документа here-document, но яделатьвидите, что вы можете значительно упростить другие вещи в своем скрипте (что, в свою очередь, делает here-document устаревшим).
Прежде всего, конвейер для заполнения вашего getHosts
массива может быть упрощен (редко возникает необходимость grep
в конвейере awk
), а весь массив можно удалить:
curl -s 'http://assetts.lab/all_hosts' |
awk -F ' ' '!/^#/ && $1 ~ /db/ { print $1 }' |
while IFS= read -r remote; do
# rest of code
done
Здесь я объединил вашу команду grep
++ в одну команду. Я также позволил команде напрямую передавать имена хостов в цикл, а не сохранять их в промежуточной переменной awk
.grep
awk
awk
Внутри цикла это выглядит так, как будто вы хотите получить информацию о rsync
процессе, iasync
принадлежащем пользователю research
.
Лучше всего это сделать с помощью pgrep
:
pgrep -l -U research 'rsync|iasync'
Чтобы обозначить эти процессы, используйте pkill
вместо pgrep
и опустите -l
опцию.
Полный сценарий будет выглядеть так:
#!/bin/sh
curl -s 'http://assetts.lab/all_hosts' |
awk -F ' ' '!/^#/ && $1 ~ /db/ { print $1 }' |
while IFS= read -r remote; do
printf 'Processing host "%s"\n' "$remote"
ssh "$remote" 'pgrep -l -U research "rsync|iasync"'
done
Или, используя xargs
:
#!/bin/sh
curl -s 'http://assetts.lab/all_hosts' |
awk -F ' ' '!/^#/ && $1 ~ /db/ { print $1 }' |
xargs -I {} sh -c '
printf "Processing host \"%s\"\n" "$1"
ssh "$1" "pgrep -l -U research \"rsync|iasync\""' sh {}
Если вы xargs
это поддерживаете, то можно запустить несколько sh -c
процессов одновременно с помощью -P n
, где n
— количество одновременно выполняемых sh -c
команд .xargs
решение2
Функция EOF в bash в основном предназначена для использования так, как вы это делаете в своем примере, то есть для отправки нескольких строк текста другой команде.
Если вы хотите, чтобы это было однострочным, то EOF придется убрать.
Чтобы выполнить команду на удаленном хосте с помощью ssh, вам нужно сделать следующее:
ssh host command
Например:
ssh host "ls -alh"
выполнит команду на хосте и вернет вывод на консоль.
Ваш пример кода можно было бы переписать в одну строку, если бы вы обратили внимание на то, как вы используете кавычки, например так:
ssh host "ps -ef | egrep 'rsync|iasync' | awk -F' ' '{if (\$1 ~ \"research\") print \$2}'"
Эта строка в двойных кавычках помещает аргументы отдельных команд в одинарные кавычки. Когда требуется больше двойных кавычек (шаблон "research
"), их нужно экранировать с помощью \
, и то же самое касается $
символов.