Intereting Posts
Arch: Все предупреждения рассматриваются как ошибки? Возможно переименование текущего каталога из оболочки? Как получить пароль без пароля ssh между любыми двумя узлами в кластере серверов Рок-стабильная файловая система для больших файлов (резервное копирование) для Linux Как заблокировать определенный URL-адрес на маршрутизаторе DD-WRT? Получение неправильного ответа с даты через awk IPTables против AF_PACKET носки Как работает перенаправление этой команды? Текстовый навигатор файлов с поиском по типу Как предотвратить видеодрайвер модуля ядра для проверки конкретного устройства графической карты Какой поток использует перцепция? Как уменьшить жадность регулярного выражения в AWK? Могу ли я использовать PXE без DHCP, просто указав статический IP-адрес вручную? Сохранять определенный результат для переменной оболочки Эвристика для использования или отклонения старой документации

Как безопасно скопировать 5 самых последних файлов в локальный каталог

У меня есть эта единственная строка кода

scp -r ${server}:${server_dir}/$(ssh ${server} "ls -t ${server_dir} | head -5") logs/ios 

который при запуске будет отображать только самый последний из пяти файлов со следующим выводом

 iosTestOutput_20180831-175508-PDT.tgz 100% 199KB 21.7MB/s 00:00 cp: iosTestOutput_20180831-155546-PDT.tgz: No such file or directory cp: iosTestOutput_20180831-142509-PDT.tgz: No such file or directory cp: iosTestOutput_20180831-124259-PDT.tgz: No such file or directory cp: iosTestOutput_20180831-115001-PDT.tgz: No such file or directory 

Тем не менее, я на самом деле ssh-ed в целевой каталог и заметил, что эти файлы существуют, поэтому я не совсем уверен, что я делаю неправильно.

Только первый файл имеет абсолютный путь к scp.

${server}:${server_dir}/$(ssh ${server} "ls -t ${server_dir} | head -5") будет оцениваться как

 ${server}:${server_dir}/iosTestOutput_20180831-175508-PDT.tgz iosTestOutput_20180831-155546-PDT.tgz iosTestOutput_20180831-142509-PDT.tgz ... 

Я использовал возвраты строк вместо пробелов для ясности.

По сути, вам нужно иметь цикл над списком, созданным с помощью чего-то, что выводит полный путь для каждого из пяти файлов. https://unix.stackexchange.com/a/240424/162359 может быть хорошим началом.

(непроверенный, просто набросок) Что-то вроде:

 for bkp in $(ssh ${server} "find ${absolute_path_remote_dir} -type f -exec stat -c '%X %n' {} \; | sort -nr | awk 'NR==1,NR==5 {print $2}'") do scp -r ${bkp} logs/ios done 

В rsync также может быть опция, которая поможет вам выполнить то, к чему вы стремитесь, более элегантно.

Когда ты побежал:

 scp -r ${server}:${server_dir}/$(ssh ${server} "ls -t ${server_dir} | head -5") 

… первой (важной) вещью, которая произошла, было то, что ваша локальная shell начала интерпретировать подстановку команд здесь:

 $(ssh ${server} "ls -t ${server_dir} | head -5") 

Вышеупомянутая подстановка команд в основном делает то, что вы думаете, за исключением того, что она прерывается, как только в имени файла есть пробел или символ новой строки (или табуляция). Например, у вас могут быть 5 последних файлов:

  • temp file
  • a
  • b
  • c
  • d

ssh ... ls -t | head -5 ssh ... ls -t | head -5 даст вам:

 a b c d temp file 

… но подстановка команды удаляет символы новой строки из вывода, оставляя вас с возвращаемой строкой:

 abcd temp file 

… который теперь неотличим от настоящих, оригинальных имен файлов.

Вы можете никогда не встретить такого имени файла, но безопаснее принять меры безопасности и никогда не быть укушенным, как наоборот.

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

 server=server-name-here ## replace with your values server_dir=/tmp ## replace with your values files=($(ssh "$server" "zsh -c 'print -N -- ${server_dir}/*(om.[1,5])'" 2>/dev/null ) ) for f in ${files[1,5]} do scp "${server}:${f}" logs/ios done 

Сложнее всего получить удаленный список из пяти самых последних измененных файлов. Здесь я ssh’ing к серверу и вызываю zsh для использования его обширного механизма globbing для возврата:

  • файлы из $ {server_dir}
  • которые упорядочены по времени модификации
  • и являются обычными файлами ( . )
  • и только первые пять: [1,5]

Встроенная команда print zsh используется здесь, чтобы вернуть разделенный нулями – и заканчивающийся нулем – список результирующих файлов. Эта строка, содержащая нуль, передается обратно через ssh в zsh, который разбивает строку на нули и присваивает содержимое массиву files .

Затем мы перебираем этот массив, стараясь захватить только первые пять элементов (поскольку шестой является нулевым значением), а затем вызываем scp для каждого из этих файлов по очереди.

Если вы хотите, вы можете аккуратно создать строку из удаленных имен файлов ( ${server}:${file1} ${server}:${file2} ... ) и вызвать scp только один раз. Одна возможность может быть:

 scp ${server}:${(qq)^files[1,5]} logs/ios 

… так как это указывает zsh добавить строку ($ {server}, которая заменяется вашим реальным именем сервера, а затем двоеточием) к первым пяти элементам массива. Все имена файлов из массива заключаются в кавычки.

Как сказал hhoke1, вам не хватает абсолютного пути.

ls -t | head -5 | xargs readlink -f

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