Как мне объединить -I и -n с xargs? - PullRequest
0 голосов
/ 10 мая 2018

Я хочу переместить большой набор файлов, используя find и xargs.Обычно я делаю это:

find /foo -name 'bar*' | tr '\n' ' ' | xargs -I % echo mv % /dest

Однако, когда слишком много файлов для перемещения, я достигаю предела количества аргументов для передачи mv.xargs имеет -n, что, кажется, было бы идеально для этого:

$ echo {0..9} | xargs -n 3 echo
0 1 2
3 4 5
6 7 8
9

Однако -I подразумевает -L 1, поэтому я не могу использовать -I с -n:

$ echo {0..9} | xargs -n 3 -I % echo % /dest
0 1 2 3 4 5 6 7 8 9 /dest

Я надеялся на такое поведение:

$ echo {0..9} | xargs -n 3 -I % echo % /dest
0 1 2 /dest
3 4 5 /dest
6 7 8 /dest
9 /dest

Возможно ли это с xargs?У меня нет GNU Parallel на моих машинах.

Ответы [ 3 ]

0 голосов
/ 12 мая 2018

С GNU Parallel вы должны сделать:

find /foo -name 'bar*' |
  parallel -X echo mv {} /dest

Это работает для имен файлов, содержащих ', "и пробел. Если имена файлов содержат' \ n ', вам придется прибегнуть к:

find /foo -name 'bar*' --print0 |
  parallel -0 -X echo mv {} /dest

Если на вашем компьютере нет GNU Parallel и у вас нет прав для установки программного обеспечения с правами root, вы можете выполнить личную установку:

wget https://ftpmirror.gnu.org/parallel/parallel-20180422.tar.bz2
bzip2 -dc parallel-20180422.tar.bz2 | tar xvf -
cd parallel-20180422
./configure --prefix=$HOME && make && make install

Или вы можете использовать --embed на машине с GNU Parallel, а затем скопировать полученный скрипт на другую машину:

parallel --embed > new_script
# Change the end of new_script
# Copy new_script to the other machine
0 голосов
/ 12 мая 2018

Если вы ищете обычные файлы с find, вы должны использовать -type f, или вы можете найти каталоги. Здесь нет необходимости использовать xargs, поскольку у вас уже есть эта способность, встроенная в find.

С GNU mv:

find /foo -type f -name 'bar*' -exec mv -t /dest {} +

Это не обнаружит, что целевой файл с таким именем уже существует. Для этого используйте

find /foo -type f -name 'bar*' -exec sh -c '
    for name do
        destname="/dest/${name##*/}"
        if [ ! -f "$destname" ]; then
            mv "$name" "$destname"
        else
            printf '%s exists already, will not copy %s\n' "$destname" "$name" >&2
        fi
    done' sh {} +

Это приведет к отказу перемещать файлы, которые будут перезаписывать файлы в /dest (и сообщать об этом).

Эти команды будут работать со всеми действительными именами файлов Unix.

0 голосов
/ 10 мая 2018

Команда mv (по крайней мере из Linux coreutils) имеет удобный флаг -t, который идеально подходит для этого варианта использования:

find /foo -name 'bar*' | tr '\n' ' ' | xargs mv -t /dest

Выше также поддерживает сохранение любого чудного имени файла без имени файла massaging :

find /foo -name 'bar*' -print0 | xargs -0 mv -t /dest

Если по какой-либо причине вы хотите использовать mv как обычно, ниже также может работать (т. Е. Использовать sh scriptlet , чтобы «потреблять» все аргументы ($@)):

find /foo -name 'bar*' | tr '\n' ' ' | xargs sh -c 'mv "$@" /dest' --
...