sh recursive copy (cp -r) – Как исключить подпапку

Мне нужно запустить удаленный скрипт, используя ssh через Ruby ( net / ssh ), чтобы рекурсивно скопировать папку и исключить подпапку. Я ищу самый быстрый способ сделать это, чтобы rsync не был хорош. Также я понимаю, что ssh использует sh а не bash .

В Bash я делаю:

 cp -r srcdir/!(subdir) dstdir 

и работает нормально. Однако, когда я запускаю скрипт через ssh я получаю сообщение об ошибке

 sh: 1: Syntax error: "(" unexpected 

потому что он использует sh .

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

Это мое предположение о том, что ssh использует sh правильно? Любое альтернативное предложение?

РЕДАКТИРОВАТЬ 1: Если это полезно, вывод sudo cat /etc/shells следующий:

 # /etc/shells: valid login shells /bin/sh /bin/dash /bin/bash /bin/rbash /usr/bin/tmux /usr/bin/screen 

РЕДАКТИРОВАТЬ 2: ОК. Так что Bash это доступно, и это, кажется, не проблема. Я убедился, что ssh на самом деле использует bash . Эта проблема, по-видимому, связана с удалением скобок или восклицательного знака. Я попытался запустить команду из оболочки (MacOS), и это фактическая команда:

 ssh -i .ssh/key.pem ubuntu@XXXX 'mkdir /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; cp -r /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!\(constant\) /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; ln -s /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/constant /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N/constant' 

Таким образом я получаю другую ошибку

 cp: cannot stat '/home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!(constant)': No such file or directory 

РЕДАКТИРОВАТЬ 3: На основе комментариев я изменил мою команду, добавив extglob

Если я использую

 ssh -i .ssh/key.pem ubuntu@XXXX 'shopt -s extglob; mkdir /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; cp -r /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!\(constant\) /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N; ln -s /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/constant /home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/N/constant' 

Я получаю следующую ошибку:

 cp: cannot stat '/home/ubuntu/OpenFOAM/ubuntu-4.1/run/LES_New-Area_residuals2/mesh/!(constant)': No such file or directory 

Если я не уйду в скобки

 bash: -c: line 0: syntax error near unexpected token `(' 

SSH запускает вашу оболочку входа в систему в удаленной системе, что бы это ни было. Но !(foo) требует shopt -s extglob , который вы, возможно, не установили на пульте дистанционного управления.

Попробуйте это, чтобы увидеть, если SSH запускает Bash на удаленной стороне:

 ssh me@somehost 'echo "$BASH_VERSION"' 

Если это что-то печатает, но ваши сценарии запуска не устанавливают extglob , вы можете сделать это вручную с помощью команды, переданной ssh :

 ssh me@somehost 'shopt -s extglob echo srcdir/!(subdir)' # or ssh me@somehost $'shopt -s extglob\n echo srcdir/!(subdir)' 

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

 ssh me @ somehost 'shopt -s extglob;  echo srcdir /! (subdir) '

Также не то, что если вы избежите скобок с обратной косой чертой, они теряют свои особые свойства, как и любые другие символы глобуса. Это не то, что вы хотите сделать в этом случае.

 $ touch foo bar; shopt -s extglob; set +o histexpand $ echo * bar foo $ echo !(foo) bar $ echo \* * $ echo !\(foo\) !(foo) 

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

Как говорится в руководстве по bash !(patter) распознается только в bash, если установлен extglob . В вашем примере вы не установили extglob . Далее, bash запущен, так как sh по-прежнему bash , но отключит некоторые расширения для совместимости.

Сервер SSH запустит оболочку входа пользователя, как указано в /etc/passwd . Вы можете либо изменить оболочку, либо использовать ее для запуска другой оболочки, которая лучше соответствует вашим потребностям.

Сначала несколько заметок:

  • сервер ssh не запускает sh для интерпретации командной строки, отправленной клиентом, он запускает оболочку входа пользователя в систему на удаленном хосте как that-shell -c , Оболочка входа удаленного пользователя может быть любой. Имейте в виду, что некоторые оболочки, такие как tcsh , fish или rc имеют синтаксис, очень отличающийся от синтаксиса sh .
  • на самом деле это командная строка, точнее строка (которая может содержать символы новой строки, так что несколько строк). Даже если вы выполните ssh host cmd arg1 'arg 2' где cmd , arg1 и arg 2 – это три аргумента, передаваемых в ssh , ssh объединяет эти аргументы с пробелами и фактически отправляет строку cmd arg1 arg 2 в sshd , а удаленная shell разделяется это в cmd , arg1 , arg и 2 .
  • !(subdir) является оператором glob (оператор zsh -o kshglob ksh также поддерживается zsh -o kshglob и bash -O extglob ). Как и все глобусы, он исключает скрытые файлы, поэтому будьте осторожны, могут быть и другие файлы, которые он исключает.

Здесь, чтобы избежать проблем с поиском правильного синтаксиса для удаленной оболочки, вы можете указать другой оболочке запустить нужную оболочку и передать ей код через stdin (один из вариантов, перечисленных в разделе Как выполнить произвольный простой команда через ssh, не зная логин оболочки удаленного пользователя? )

 ssh host 'bash -O extglob -O dotglob' << 'EOF' cp -r srcdir/!(subdir) dstdir/ EOF 

bash -O extglob -O dotglob - это командная строка, которая понимается одинаково всеми основными shellми, включая Bourne-подобные, csh, rc, fish ... Вышеописанное будет работать, пока bash установлен и находится у пользователя. $PATH (по умолчанию $PATH , возможно измененный пользовательской оболочкой входа, например, ~/.zshenv для zsh , ~/.cshrc для csh , ~/.bashrc для bash ).

POSIXly (хотя на практике вы можете обнаружить, что больше систем имеют команду bash чем команду pax ), вы можете сделать:

 ssh host sh << 'EOF' cd srcdir && pax -rw -'s|^\.//\./subdir\(/.*\)\{0,1\}$||' .//. /path/to/destdir/ EOF 

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

Я не думаю, что ssh ограничен использованием sh . Скорее, это зависит от того, что установлено в целевой системе, как настроен пользователь и какие оболочки разрешены в /etc/shells .

Вы рассматривали команду chsh ?

Если вы хотите сделать это быстро, вы можете посмотреть на rsync с другим алгоритмом шифрования. Это дает вам возможность легко исключать и т. Д., Не жертвуя скоростью.

rsync -aHAXxv --numeric-ids --progress -e "ssh -T -c arcfour -o Compression=no -x" user@:

вместе с добавлением шифрования arcfour к строке, начинающейся с Ciphers в /etc/ssh/ssh_config , если она еще не включена, дает приемлемую скорость.

ВНИМАНИЕ: шифрование arcfour небезопасно . НЕ запускайте это по незащищенным каналам. Если вас беспокоит доступ к серверу из незащищенных каналов с использованием шифрования arcfour , измените arcfour etc/ssh/ssh_config на специфичную для хоста часть для вашего исходного хоста. Создайте раздел Host в вашем ssh_config для вашего исходного хоста, вы можете использовать Ciphers arcfour есть Ciphers arcfour чтобы отразить вышеуказанный ключ -c , который ограничивает шифрование arcfour для этого хоста.

Для получения дополнительной информации обратитесь к страницам ssh_config .

Однако, если ваши процессоры поддерживают набор инструкций AES-NI, попробуйте переключиться на aes128-gcm@openssh.com (да, это имя шифра, включая @ stuff), который будет использовать невероятно быстрый (с AES-NI) AES128 -GCM.

Итак, с процессором, поддерживающим AES-NI, замените "ssh -T -c arcfour -o Compression=no -x" на "ssh -T -c aes128-gcm@openssh.com -o Compression=no -x" чтобы "ssh -T -c aes128-gcm@openssh.com -o Compression=no -x" больше безопасные результаты.

объяснение

Rsync

  • (Не используйте -z , это намного медленнее)
  • a : режим архива – рекурсивный, сохраняет владельца, сохраняет разрешения, сохраняет время модификации, сохраняет группу, копирует символические ссылки как символические ссылки, сохраняет файлы устройств.
  • H : сохраняет жесткие ссылки
  • A : сохраняет ACL
  • X : сохраняет расширенные атрибуты
  • x : не пересекать границы файловой системы
  • v : увеличить многословие
  • --numeric-ds : не отображать значения uid / gid по имени пользователя / группы
  • если вам нужно синхронизировать, добавьте --delete : удалить посторонние файлы из директорий dest (дифференциальная очистка во время синхронизации)
  • --progress : показать прогресс во время передачи

SSH

  • T : отключить псевдо-tty, чтобы уменьшить загрузку процессора в месте назначения.
  • c arcfour : используйте самое слабое, но самое быстрое шифрование SSH. Необходимо указать “Ciphers arcfour” в sshd_config по назначению.
  • o Compression=no : отключить сжатие SSH.
  • x : отключить переадресацию X, если она включена по умолчанию.

rsync -av о параметрах ssh – если вы просто используете rsync -av и -e ssh -T -c arcfour -o Compression=no -x" , вы также можете получить эти скорости.


Сравнение:

  • 13,6 МБ / с rsync -az
  • 16,7 МБ / с scp -Cr
  • 44,8 МБ / с rsync -a
  • 59,8 МБ / с sftp
  • 61,2 МБ / с scp -r
  • 61,4 МБ / с sftp -R 128 -B 65536
  • 62,4 МБ / с rsync -a -P -e "ssh -T -c arcfour -o Compression=no -x"
  • 143,5 МБ / с scp -r -c arcfour
  • 144,2 МБ / с sftp -oCiphers=arcfour

Источники :

https://gist.github.com/KartikTalwar/4393116

http://nz2nz.blogspot.com/2018/05/rsync-scp-sftp-speed-test.html

Согласно моим расчетам, самая быстрая полная копия всегда использует ‘tar’ (здесь предполагается GNU tar или совместимый).

 mkdir -p photos2 && tar -C photos -cf - --exclude=./.thumbcache . | tar -C photos2 -xpf - 

И tar имеет множество опций для управления атрибутами, разрешениями и выбором / исключением файлов. Например, приведенная выше команда исключает подпапку верхнего уровня с именем .thumbcache при копировании.