1

У меня есть файл, где каждая строка является именем файла. Содержание файла:

file1
file2
file3
...

Затем я запускаю команду grep чтобы получить подмножество списка имен файлов.

Как передать вывод команды grep в scp? Я поиграл с xargs и $() без особого успеха ...

3 ответа3

2

Не нужно использовать xargs:

for file in $(grep <some-pattern> <filelist>); do scp $file <remote>; done;

куда

  • <some-pattern> - это ваш шаблон grep
  • <filelist> это ваш список файлов
  • <remote> - ваш удаленный конец команды scp

Цикл for будет перебирать каждую строку, grep и передавать ее в $file , которую вы можете повторно использовать в командах, выполняемых между do и done .

Также см .: Расширенное руководство по написанию сценариев Bash: - Циклы

1

Чтобы перебрать список имен файлов с одним именем в строке, у вас есть несколько возможностей:

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

    set -f; IFS='
    '
    scp -- $(…) remote.example.com:
    
  • Используйте встроенное read для обработки имен файлов в цикле. Опять же, вы должны быть осторожны, потому что read обрабатывает обратную косую черту и символы $IFS специально.

    … | while IFS= read -r x; do scp -- "$x" remote.example.com: done
    
  • Вы можете использовать GNU xargs, но вы должны действовать осторожно, потому что xargs ожидает его ввода в странно заключенном в кавычки формате. Вы должны передать опцию -d '\n' чтобы явно выбрать переводы строки в качестве разделителя ввода и отключить специальное поведение пробелов и \'" .

    … | xargs -d '\n' -I {} scp {} remote.example.com:
    

    Единственное преимущество xargs заключается в том, что он может сгруппировать несколько аргументов в один вызов до предела длины командной строки, но это работает, только если аргументы передаются команде в последнюю очередь. Вы можете достичь этого с помощью промежуточного вызова sh , но это редко стоит того.

    … | xargs -d '\n' sh -c 'scp -- "$@" "$0"' remote.example.com:
    
  • Более простой способ использования xargs - получить разделенный нулями список вместо разделенных строкой . Для этого требуется опция -0 , которая поддерживается GNU xargs, а также недавним * BSD. Как и выше, приведение аргументов в не финальную позицию требует небольшой работы.

    … | tr '\n' '\0' | xargs -0 sh -c 'scp -- "$@" "$0"' remote.example.com:
    

Часть будет выглядеть как grep NAME_REGEXP /path/to/filenames.list если вы хотите фильтровать имена файлов с помощью регулярного выражения. Если вы хотели отфильтровать содержимое файла, используйте один из методов, приведенных выше, для передачи имен файлов в grep , например:

set -f; IFS='
'
scp -- $(grep -l CONTENT_REGEXP -- $(cat /path/to/filenames.list)) \
    remote.example.com:

Другая возможность, которая обходит трудности оболочки, - это использовать rsync и его --files-from . Предполагая, что имена файлов все относительно текущего каталога:

grep NAME_REGEXP /path/to/filenames.list |
rsync -a --files-from - . remote.example.com:
0

Используйте read для разбора выходных данных построчно (https://stackoverflow.com/a/7039208); grep <some-pattern> <filelist> | while read file; do scp $file <remote>; done;

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .