Я пробовал различные комбинации xargs и piping, но я просто не могу получить правильный результат. Предыдущие вопросы не совсем касались того, чем я хочу заниматься:

  • У меня где-то есть исходный каталог, скажем / foo / source, со смесью разных файлов
  • Я хочу скопировать только файлы csv, найденные в источнике, в другое место назначения, например / foo / dest
  • Но мне ТАКЖЕ в то же время нужно удалить 232 строки заголовка (например, с помощью хвоста)

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

find /foo/source -name "*.csv" | xargs -I '{}' sh -c 'tail -n +232 | cp -t /foo/dest'

cp: отсутствует файловый операнд

find /foo/source -name "*.csv" | xargs -I '{}' sh -c 'tail -n +232 {} | cp -t /foo/dest'

Результат:

cp: не удалось получить доступ к '/ foo / dest': нет такого файла или каталога ...

find /foo/source -name "*.csv" | xargs -I '{}' sh -c 'tail -n +232 {} > /foo/dest/{}'

sh: /foo/dest/foo/source/0001.csv: нет такого файла или каталога ...

Любые указатели будут по достоинству оценены!

Благодарность

1
James Allen 6 Сен 2016 в 16:36

4 ответа

Лучший ответ

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

find /foo/source -name "*.csv" | xargs -I '{}' sh -c 'tail -n +232 {} > /foo/dest/$(basename {})'
1
Barmar 6 Сен 2016 в 14:04

Просто используйте find с exec и скопируйте имя файла в переменную:

find your_dir -name "*.csv" -exec sh -c 'f="$1"; tail -n +5 "$f" > dest_dir/$(basename "$f")' -- {} \;

См. f={} заставляет $f содержать имя файла с полным путем. Затем нужно перенаправить вывод tail в файл, удалив из него путь.

Или на основе предложения Random832 ниже в комментариях (спасибо!):

find your_dir -name "*.csv" -exec sh -c 'tail -n +5 "$1" > dest_dir/$(basename "$1")' -- {} \;
2
Community 23 Май 2017 в 12:19

В качестве альтернативы find и xargs вы можете использовать цикл for, а в качестве альтернативы tail вы можете использовать sed, учтите это:

source=/foo/source
dest=/foo/dest
for csv in $source/*.csv; do sed '232,$ !d' $csv > $dest/$(basename $csv); done
1
Jorge Valentini 6 Сен 2016 в 14:31

Используя GNU Parallel, вы бы сделали:

find /foo/source -name "*.csv" | parallel tail -n +232 {} '>' /foo/dest/{/}
0
Ole Tange 23 Сен 2016 в 19:24