Тогда ответ заключается в том, что sudo
имеет ошибку. Во-первых, обходной путь: /etc/sudoers.d/zabbix
:
zabbix ALL=(root) NOPASSWD: /bin/env SHELL=/bin/sh /usr/local/bin/zabbix_raid_discovery
и теперь подкоманды, вызываемые из zabbix_raid_discovery
, работают.
Патч, исправляющий это, будет в sudo 1.8.15. От сопровождающего, Тодда Миллера:
This is just a case of "it's always been like that". There's not really a good reason for it. The diff below should make the behavior match the documentation. - todd diff -r adb927ad5e86 plugins/sudoers/env.c --- a/plugins/sudoers/env.c Tue Oct 06 09:33:27 2015 -0600 +++ b/plugins/sudoers/env.c Tue Oct 06 10:04:03 2015 -0600 @@ -939,8 +939,6 @@ CHECK_SETENV2("USERNAME", runas_pw->pw_name, ISSET(didvar, DID_USERNAME), true); } else { - if (!ISSET(didvar, DID_SHELL)) - CHECK_SETENV2("SHELL", sudo_user.pw->pw_shell, false, true); /* We will set LOGNAME later in the def_set_logname case. */ if (!def_set_logname) { if (!ISSET(didvar, DID_LOGNAME)) @@ -984,6 +982,8 @@ if (!env_should_delete(*ep)) { if (strncmp(*ep, "SUDO_PS1=", 9) == 0) ps1 = *ep + 5; + else if (strncmp(*ep, "SHELL=", 6) == 0) + SET(didvar, DID_SHELL); else if (strncmp(*ep, "PATH=", 5) == 0) SET(didvar, DID_PATH); else if (strncmp(*ep, "TERM=", 5) == 0) @@ -1039,7 +1039,9 @@ if (reset_home) CHECK_SETENV2("HOME", runas_pw->pw_dir, true, true); - /* Provide default values for $TERM and $PATH if they are not set. */ + /* Provide default values for $SHELL, $TERM and $PATH if not set. */ + if (!ISSET(didvar, DID_SHELL)) + CHECK_SETENV2("SHELL", runas_pw->pw_shell, false, false); if (!ISSET(didvar, DID_TERM)) CHECK_PUTENV("TERM=unknown", false, false); if (!ISSET(didvar, DID_PATH))
Только первый файл имеет абсолютный путь, необходимый scp.
${server}:${server_dir}/$(ssh ${server} "ls -t ${server_dir} | head -5")
оценивается как
${server}:${server_dir}/iosTestOutput_20180831-175508-PDT.tgz
iosTestOutput_20180831-155546-PDT.tgz
iosTestOutput_20180831-142509-PDT.tgz
...
Для ясности я использовал символы возврата строки вместо пробелов.
По сути, вам нужно иметь цикл по сгенерированному списку, используя что-то, что выводит полный путь для каждого из пяти файлов.https://unix.stackexchange.com/a/240424/162359может быть хорошим началом.
(не проверено, просто грубый набросок )Что-то вроде:
for bkp in $(ssh ${server} "find ${absolute_path_remote_dir} -type f -exec stat -c '%X %n' {} \; | sort -nr | awk 'NR==1,NR==5 {print $2}'")
do
scp -r ${bkp} logs/ios
done
В rsync также может быть некоторая опция, которая поможет вам сделать то, что вы хотите, более элегантно.
Когда ты бежал:
scp -r ${server}:${server_dir}/$(ssh ${server} "ls -t ${server_dir} | head -5")
... первая (важная )вещь, которая произошла, заключалась в том, что ваша локальная оболочка начала интерпретировать подстановку команд здесь:
$(ssh ${server} "ls -t ${server_dir} | head -5")
Приведенная выше подстановка команд в основном делает то, что вы думаете, за исключением того, что она прерывается, как только в имени файла появляется пробел или новая строка (или табуляция ). Например, у вас могут быть эти 5 последних файлов:
temp file
a
b
c
d
ssh... ls -t | head -5
даст вам:
a
b
c
d
temp file
... но подстановка команды удаляет новые строки из вывода, оставляя вам возвращаемую строку:
a b c d temp file
... которое теперь неотличимо от настоящих, оригинальных имен файлов.
Вы можете никогда не встретить такое имя файла, но безопаснее считать себя в безопасности и никогда не быть укушенным, чем наоборот.
В результате я бы предложил направление, в котором вы безопасно извлекаете имена файлов в локальную систему, а затем специально извлекаете их:
server=server-name-here ## replace with your values
server_dir=/tmp ## replace with your values
files=($(ssh "$server" "zsh -c 'print -N -- ${server_dir}/*(om.[1,5])'" 2>/dev/null ) )
for f in ${files[1,5]}
do
scp "${server}:${f}" logs/ios
done
Самое сложное — получить удаленный список пяти последних -измененных файлов. Здесь я подключаюсь к серверу по ssh и вызываю zsh, чтобы использовать его обширный механизм подстановки для возврата:
o
упорядочены по m
времени модификации .
)[1,5]
Команда zsh, встроенная -в print
, используется здесь для возврата нулевого -разделенного --и нулевого -завершенного списка результирующих файлов. Эта строка, содержащая нуль -, передается обратно через ssh к zsh, который разбивает строку на пустые значения и присваивает содержимое массиву files
.
Затем мы перебираем этот массив, стараясь захватить только первые пять элементов (, так как шестой имеет нулевое значение ),затем вызовите scp
для каждого из этих файлов по очереди.
Если вы хотите, вы можете тщательно создать строку имен удаленных файлов(${server}:${file1} ${server}:${file2}...
)и вызвать scp
только один раз. Возможно,:
scp ${server}:${(qq)^files[1,5]} logs/ios
... так как это указывает zsh добавить перед первыми пятью элементами массива строку (${server}, которая заменяется вашим реальным именем сервера, за которым следует двоеточие ). Любые имена файлов из массива заключаются в кавычки.
Как сказал hhoke1, у вас отсутствует абсолютный путь.
ls -t | head -5 | xargs readlink -f
Это должно дать вам абсолютный путь для scp, но похоже readlink
не может прочитать ввод из канала, поэтому я использовал xargs
.