Одна вещь принять во внимание состоит в том, что имя файла передается неизмененное оболочке входа в систему удаленного пользователя.
Если Вы делаете:
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 или больше из предыдущего атома))
В данном случае
scp 'user@host:file-name-version-*[0-9].jar' .
мог бы быть достаточно для Вас.