У меня есть такие файлы:
A.class
A$1.class
A$2.class
И сценарий bash с чем-то вроде:
for i in *; do
scp "${i}" foo@bar:/tmp/;
done
Это прекрасно работает. Копируются все три файла. Проблема в следующем:
for i in *; do
scp "${i}" foo@bar:/tmp/"${i}";
scp "${i}" foo@bar:"/tmp/${i}";
scp "${i}" "foo@bar:/tmp/${i}";
done
В любом из этих случаев SCP копирует все файлы, но в тот же файл. Класс.
Любые идеи? Спасибо!
С помощью scp -v
показывает некоторые подробности о том, как работает scp:
debug1: Sending command: scp -v -t /tmp/A$2.class
Sending file modes: C0644 0 A$2.class
Sink: C0644 0 A$2.class
A$2.class 100% 0 0.0KB/s 00:00
По сути, поскольку scp работает поверх ssh, ему нужна оболочка для выполнения вашей команды, а поскольку $
не экранирован, удаленная оболочка интерпретирует $2
как пустая строка, что делает целевое имя A.class
.
Есть два способа исправить это. Во-первых, вы можете просто использовать *
glob напрямую в команду scp:
scp * foo@bar:/tmp/
Но я почти уверен, что у вас есть другие потребности в использовании цикла, поэтому вот как исправить это в цикле:
for i in *; do
scp "${i}" "foo@bar:'/tmp/${i}'"
done
Проверка вывода scp -v
теперь показывает:
debug1: Sending command: scp -v -t '/tmp/A$2.class'
Успех! Одиночные кавычки не позволяют удаленной оболочке выполнять раскрытие переменных.
ОБНОВЛЕНИЕ: поскольку аргумент интерпретируется оболочкой как аргумент, вы можете делать такие вещи, как это:
scp foo@bar:'$(which ssh)' .
Или даже более сложные конвейеры оболочки, которые приводят к имени файла. Это не проблема безопасности, так как если вы можете подключиться с помощью scp, вы можете подключиться с помощью ssh. Но кому-то это может сделать жизнь удобнее.
Одним из решений было бы использовать для этого find:
find . -name A\*.class -print0|xargs -0 -i _PLACEHOLDER_ scp _PLACEHOLDER_ foo@bar:/tmp/_PLACEHOLDER_
Идея состоит в том, чтобы избежать расширения оболочки.
Я думаю это вызвано "${i}"
расширяется на местном уровне до A$1.class
а затем отправляется на пульт, который расширяет его до A.class
как $1
является ""
. Вы можете обойти это с
scp "${i}" foo@bar:/tmp/'${i}';