Исключите символы для SCP-filepattern

В процессе создания printerd очень очень бета в mo, стоящем упоминания хотя,

2
04.10.2016, 13:23
4 ответа

Одна вещь принять во внимание состоит в том, что имя файла передается неизмененное оболочке входа в систему удаленного пользователя.

Если Вы делаете:

 scp user@remote-machine:'something' ...

На удаленной машине, sshd выполнит оболочку входа в систему user как:

 that-shell -c 'scp -f something'

И это - которые окружают, который развернет шаблоны там.

То, что это означает, - то, что способ, которым расширен шаблон, будет зависеть, на какой оболочке входа в систему удаленный пользователь использует. Когда та оболочка bash, это будет также зависеть от того, что пользователь имеет в его ~/.bashrc, или что существует в /etc/bash.bashrc (например, bash-completion названный оттуда при установке включает ksh-стиль расширенный globbing), с тех пор по некоторым причинам bash чтения те при вызывании ssh (даже при том, что это не интерактивная оболочка).

То, что это также означает, является этим если something например, 'blah; rm -rf "$HOME"', это будет иметь катастрофические последствия.

Это - один из misdesigns ssh.

Если Вы хотите вынудить определенную оболочку развернуть это something в список файлов можно использовать этот прием:

LC_SCPFILES=something scp -o SendEnv=LC_SCPFILES "localhost:</dev/null
  bash -O extglob -c 'exec scp -f -- \$LC_SCPFILES';exit" /dest/dir

Тот единственные работы, если оболочка входа в систему удаленного пользователя является нормальной оболочкой Unix (Границы, csh, дистанционного управления или семейств рыбы, по крайней мере), и bash установлен там и sshd позволяет передающие переменные среды, имя которых запускается с LC_.

Прием то, что большинство sshd развертывание позволяет передающие переменные среды, имя которых запускается с LC_ (необходимый так, чтобы испанский пользователь мог получить сообщения об ошибках от удаленных команд на испанском языке (вместо языка по умолчанию в удаленной системе или языка удаленного пользователя), например).

Таким образом, здесь, мы передаем something в a LC_SCPFILES переменная среды.

На удаленной машине, sshd будет работать:

that-shell -c 'scp -f </dev/null
  bash -O extglob -c '\''exec scp -f -- $LC_SCPFILES'\'';exit'

Поскольку его stdin перенаправляется от /dev/null, первое scp немедленно выйдет. Затем мы запускаем нашу предпочтительную оболочку (bash), с extglob опция, и с exec scp -f -- $LC_SCPFILES командная строка для интерпретации.

Поскольку bash будет работать в дочернем процессе that-shell (который мы осуществляем путем добавления a ;exit впоследствии), bash не получит ~/.bashrc, таким образом, мы можем ожидать поведение по умолчанию bash там (если так или иначе that-shell, на запуске, наборы BASHOPTS, SHELLOPTS или BASH_ENV переменные среды).

Поскольку $LC_SCPFILES не заключается в кавычки, это подвергнется разделению слова и поколению имени файла (globbing), но не другим расширениям оболочек, и это не сделает, вещам нравится rm -rf "$HOME" просто, потому что something содержит его.

Теперь, когда мы удостоверились, что шаблон расширен bash -O extglob на удаленной машине мы можем использовать его для соответствия шаблону, который использует расширенные операторы шарика (здесь использующий функцию помощника):

safer_scp() (
  file=$1; shift
  export LC_SCPFILES="${file#*:}"
  exec scp -o SendEnv=LC_SCPFILES "${file%%:*}:</dev/null
    bash -O extglob -c 'exec scp -f -- \$LC_SCPFILES';exit" "$@"
)
safer_scp user@host:'file-name-version-+([0-9]).+([0-9]).+([0-9]).jar' .

+([0-9]), с extglob на в bash соответствия одна или несколько десятичных цифр. Таким образом, шаблон выше соответствовал бы file-name-version-1.2.3.jar и file-name-version-12.123.1234.jar например.

(обратите внимание что safer_scp выше предполагает, что первый аргумент host:file-patterns, вещи как safer_scp -r ... или safer_scp host1:f1 host2:f2 ... не будет работать. Если Вы хотите использовать -r, самое легкое должно определить a safer_scp_r функция, где scp -f выше заменяется scp -r -f).

Обратите внимание, что можно отключить разделение слова путем добавления a IFS=; перед exec scp... выше.

Также обратите внимание, что мы используем bash здесь на основании, что это установлено во всех системах GNU, но если Вы знаете zsh установлен в удаленной системе, можно использовать

zsh -o extendedglob -o globsust

вместо этого извлечь выгоду из полной мощности zsh globbing (рекурсивный, спецификаторы...)

(добавьте -o shwordsplit если Вы хотите слово, разделяющее также).

Например:

safer_scp() (
  file=$1; shift
  export LC_SCPFILES="${file#*:}"
  exec scp -o SendEnv=LC_SCPFILES "${file%%:*}:</dev/null
    zsh -o extendedglob -o globsubst -c 'exec scp -f -- \$LC_SCPFILES';exit" "$@"
)
safer_scp user@host:'file-name-version-<->(.<->)#.jar' .

Скопировал бы file-name-version-1.jar и file-name-version-1.2.3.4.5.jar (<x-y> любое десятичное целое число от x кому: y, <-> любое десятичное целое число, # похож * оператор regexp (0 или больше из предыдущего атома))

5
27.01.2020, 21:51
  • 1
    Святая корова, которая является потрясающим ответом! –  Vince 29.11.2013, 15:34

Я думаю, что Вы хотите

file-name-version-[0-9].[0-9].[0-9].jar
1
27.01.2020, 21:51
  • 1
    Большой, это точно, что я искал!Спасибо! –  Vince 29.11.2013, 13:40
  • 2
    Обратите внимание, что это не будет работать на 1.10.2. –  Stéphane Chazelas 29.11.2013, 14:29

В данном случае

scp 'user@host:file-name-version-*[0-9].jar' .

мог бы быть достаточно для Вас.

1
27.01.2020, 21:51

Для гибкости используйте rsync вместо scp.

rsync --include='file-name-*.jar' \
      --exclude='*-sources.jar' --exclude='*-javadoc.jar' \
      example.com:/some/directory/ local/directory/
1
27.01.2020, 21:51

Теги

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