Как правильно экранировать пробелы из нескольких файлов в команде scp из исходной функции в bash - PullRequest
0 голосов
/ 19 декабря 2018

Я построил функцию в моем .bashrc, которая прерывается, когда он пытается найти файлы с пробелами в именах, но если я запускаю сгенерированную команду, выводимую из функции в командной оболочке напрямую, она, похоже, работает нормально.

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

От.bashrc

push2() {
    # parse args, build file list, get suffix from final arg
    files=""
    i=1
    orig_IFS=$IFS; IFS=":"
    for arg in $*; do
        if [ "$i" = "$#" ]; then
            suffix=$arg
        else
            files="$files $(echo $arg | sed -r 's/ /\\ /')" #escape spaces
        fi
        i=$(($i+1))
    done
    IFS=$orig_IFS
    # determine prefix and proxy
    gen_prefix $suffix
    # output generated command for debugging
    echo "scp $scp_proxy$files testuser@$prefix$suffix:"
    # run command
    scp $scp_proxy$files testuser@$prefix$suffix:
}

Кажется, что запуск функции по-прежнему завершается ошибкой, даже если строка выходной команды выглядит правильно экранированной

root@DHCP-137:~$ push2 temp* 42
scp  temp temp\ file testuser@10.3.3.42:
temp                                          100% 6008     1.1MB/s   00:00 
temp\: No such file or directory
file: No such file or directory

Запуск генерируемой команды работает как ожидалось

root@DHCP-137:~$ scp  temp temp\ file testuser@10.3.3.42:
temp                                          100% 6008   896.4KB/s   00:00 
temp file                                     100%    0     0.0KB/s   00:00 
root@DHCP-137:~$ 

Дополнительная информация: GNU bash, версия 4.4.12 (1) -релиз (x86_64-pc-linux-gnu) - работает на Debian 9

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

Во-первых, измените свою подпись вызова так, чтобы суффикс пришел first :

push2 42 ./temp*

Тогда функция должна быть определена просто как

push2 () {
  local -a scpProxy
  local prefix suffix
  suffix=$1
  shift

  gen_prefix "$suffix"

  scp "${scpProxy[@]}" "$@" "testuser@$prefix.$suffix:"
}

где gen_prefix выглядит примерно так:

gen_prefix () {
  case $1 in
     42) scpProxy=()
         prefix=10.3.3
         ;;
     89) scpProxy=(-o ProxyJump=user@server)
         prefix=123.456.789
         ;;
  esac
}

После вызова shift, $@ содержит только файлы, которые вы хотите передать.scpProxy - это массив, содержащий несколько отдельных аргументов для передачи scp;если он пуст, то "${scpProxy[@]}" расширится до 0 аргументов, а не пустой строки.

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

Хотя gen_prefix, кажется, определяет свои переменные "глобально", на самом деле он просто определяет их в любой области видимости gen_prefix, , называется from (bash используетдинамическая область видимости, а не лексическая область видимости, как в большинстве других распространенных языков).Два вызова local гарантируют, что все, что назначит gen_prefix, останется внутри push2 и не будет видно после выхода push2.


В качестве дополнительного примечания большая часть этой функции может исчезнутьс подходящей конфигурацией ssh.Учтите это в вашем .ssh/config файле:

Host somehost
    User testuser
    Hostname 10.3.3.42

Host someotherhost
    User testuser
    Hostname 123.456.789.89
    ProxyJump user@server

Теперь вам не нужно push2 вообще;просто запустите

scp temp* somehost:

или

scp temp* someotherhost:

, и правильные адреса и параметры будут использованы автоматически.Конфигурация ssh заменяет все, что gen_prefix сделал, и без необходимости вызывать gen_prefix больше нет необходимости переносить scp.

0 голосов
/ 19 декабря 2018

Все было исправлено, изменив последнюю строку

scp $scp_proxy$files testuser@$prefix$suffix:

и обернув ее в eval, подобный этому

eval "scp $scp_proxy$files testuser@$prefix$suffix:"
...