Передача строки сценария в ssh из функции сценария bash - проблема оценки переменных

Можно циклично выполниться через все каталоги включая скрытые каталоги (начинающийся с точки) в одной строке и нескольких командах с:

for file in */ .*/ ; do echo "$file is a directory"; done

Если Вы хотите исключить символьные ссылки:

for file in *; do 
  if [[ -d "$file" && ! -L "$file" ]]; then
    echo "$file is a directory"; 
  fi; 
done

примечание: использование списка */ .*/ работы в ударе, но также и дисплеи папки . и .. в то время как в zsh это не покажет их, но бросит ошибку, если не будет никакого скрытого файла в папке

Более чистая версия, которая будет включать скрытые каталоги и исключать../, будет с dotglob опцией:

shopt -s dotglob
for file in */ ; do echo "$file is a directory"; done

(или setopt dotglob в zsh)

можно сбросить dotglob с

shopt -u dotglob
3
05.10.2015, 01:12
2 ответа

Вот версия, которая была упрощена и, что более важно, исправлено цитирование (двойные кавычки вокруг переменных, одинарные кавычки вокруг непеременного текста, где требуется)

#!/bin/bash
logfilepattern='*drupal*.gz php*.gz error*.gz'

function getlogcounts {
    echo in getlogcounts
    echo "$1"
    echo "$2"

    ssh "$1" "cd $2 ; ls -l $logfilepattern"
}

getlogcounts me@remoteserver.com /var/log/mylogs
2
27.01.2020, 21:19

Вы выполняете сценарий на удаленной машине. Этот сценарий содержит $2 и $logfilepattern (текст между одинарными кавычками передается буквально как аргумент команды ssh, так что это фрагмент кода для выполнения на другой стороне). Они относятся к переменным оболочки, запущенной на стороне удаления.

На самом деле, вы запускаете две оболочки на удаленной стороне, но это не очень полезно. SSH всегда вызывает оболочку; вы можете передать ей несколько аргументов, но они просто соединяются с пробелами между ними. Оболочка на удаленной стороне выполняет

bash -c   \  #script string starts here
cd $2
…

Первая строка вызывает bash с двумя аргументами: -c и один пробел. Это вызывает оболочку, которая ничего не делает. Остальная часть удаленной команды выполняется в оболочке, вызванной SSH.

Простой способ сделать то, что вы пытаетесь сделать, следующий

ssh "$1" "cd $2 && ls -l $logfilepattern"

Примечания:

  • Разбор вывода ls бессмыслен: for file in `ls *` - это сложный способ написать for file in *, за исключением того, что разбор вывода ls ломается, если имена файлов содержат специальные символы.
  • И $2, и $logfilepattern анализируются как часть сценария, выполняемого на удаленной стороне. Если они содержат что-то вроде $(touch foo), то этот фрагмент кода будет выполнен. В данном конкретном случае это не обязательно является проблемой, но вы должны знать об этом.
  • Использование && после cd гарантирует, что команда ssh немедленно вернется со статусом отказа, если команда cd не выполнится.

Если вы хотите передать содержимое без изменений в удаленную оболочку по SSH, использование только командной строки проблематично, поскольку все, что вы передаете, расширяется на удаленной стороне. Один трюк, который часто работает (но не всегда, это зависит от конфигурации SSH как на клиенте, так и на сервере) - использовать переменные, имя которых начинается с LC_; предполагается, что это информация о локали, и часто она передается.

LC_DIRECTORY=$2 LC_LOGFILEPATTERN=$logfilepattern ssh "$1" 'cd "$LC_DIRECTORY" && ls -l $LC_LOGFILEPATTERN'

Обратите внимание на кавычки:

  • Команда для выполнения на удаленной машине - cd "$LC_DIRECTORY" && ls -l $LC_LOGFILEPATTERN. Он заключается в одинарные кавычки, чтобы передать этот буквальный текст в качестве аргумента команде ssh.
  • $LC_DIRECTORY заключается в двойные кавычки в сценарии, который выполняется на удаленной стороне, чтобы команда cd была вызвана на содержимом переменной.
  • LC_LOGFILEPATTERN не заключен в двойные кавычки, потому что это список шаблонов, разделенных пробелами, а именно так трактуется расширение переменной без кавычек.

Если вы не можете передавать переменные, вам придется добавить уровень цитирования для защиты переменных, значение которых содержит специальные символы.

q_directory=$(printf %sa "$2" | sed s/\'/\'\\\'\'/g)
q_directory="'${directory%a}'"
q_logfilepattern=$(printf %sa "$logfilepattern" | sed s/\'/\'\\\'\'/g)
q_logfilepattern="'${q_logfilepattern%a}'"
ssh "$1" "logfilepattern=$q_logfilepattern; cd $q_logfilepattern && ls \$logfilepattern"
2
27.01.2020, 21:19

Теги

Похожие вопросы