Як використовувати> в команді xargs?


160

Я хочу знайти команду bash, яка дозволить мені знімати кожен файл у каталозі та записувати вихід цього grep в окремий файл. Думаю, було б зробити щось подібне

ls -1 | xargs -I{} "grep ABC '{}' > '{}'.out"

але, наскільки я знаю, xargs не любить подвійних лапок. Якщо я видаляю подвійні лапки, тоді команда перенаправляє вихід всієї команди до одного файлу під назвою '{}'.

Хтось знає про спосіб зробити це за допомогою xargs? Я просто використав цей сценарій grep як приклад, щоб проілюструвати свою проблему з xargs, тому будь-які рішення, які не використовують xargs, не є для мене застосовними.

Відповіді:


201

Не робіть помилки, роблячи це:

sh -c "grep ABC {} > {}.out"

Це порушиться за багатьох умов, включаючи прикольні назви файлів, і це неможливо правильно цитувати. Ви {}завжди повинні бути єдиним повністю окремим аргументом команди, щоб уникнути помилок введення коду. Що вам потрібно зробити, це:

xargs -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}

Застосовується xargsяк до, так і до find.

До речі, ніколи не використовуйте xargs без цього -0варіанту (за винятком дуже рідкісного та контрольованого одноразового інтерактивного використання, коли ви не турбуєтесь про знищення своїх даних).

Також не розбирайте ls. Колись. Використовуйте глобулінг або findзамість цього:http://mywiki.wooledge.org/ParsingLs

Використовуйте findдля всього, що потребує рекурсії, і простого циклу з глобусом для всього іншого:

find /foo -exec sh -c 'grep "$1" > "$1.out"' -- {} \;

або нерекурсивні:

for file in *; do grep "$file" > "$file.out"; done

Помітьте належне використання цитат.


Запропонований, але сумнівний рег. не використовується xargsбез -0: це стосується лише тоді, коли ви маєте findвисновок труби xargs, правда? коли я роблю, xargs -a <input_file>як би це використовувати? Більшість команд на зразок grepвиходів із, \nа не \0.єдиним способом, який я можу думати над цим, - це використати trще раз, щоб виправити це. Але чому це важливо використовувати тільки з -0?
legends2k

3
@ legends2k, тому що, коли ви не використовуєте -0, xargsвізьме ваші імена файлів і порушить усі пробіли, цитати та зворотні риски в них. Про xargsінструмент слід просто забути . Якщо у вас є лінії, використовуйте цикл bash, щоб повторити лінії: while read line; do <command> "$REPLY"; done < file-with-linesабоcommand | while ...
lhunath

1
Нічого, не знав про це, дякую за деталі! Тому для портативності (оскільки не всі xargsє GNU), xargsслід уникати, якщо з ними не можна користуватися -0. Дякую.
legends2k

1
Хоча я ціную детальне пояснення цього конкретного випадку використання, питання полягає у перенаправлення виводу xargs, який не завжди передбачає розбір lsабо використання sh -c. Це не дає відповіді на найменше, але це перший результат google для запитання, лише додаючи плутанини.
pandasauce

1
@Ihunath, Привіт, твоя відповідь добре працює для мене. Але ви могли б дати детальне пояснення чи посилання xargs -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}? Особливо, правила вбудованих (подвійних) лапок та символу "-" наприкінці. Дякую
Скотт Ян

40

Рішення без xargsтакого:

find . -mindepth 1 -maxdepth 1 -type f -exec sh -c "grep ABC '{}' > '{}.out'" \;

... і те ж саме можна зробити з xargs , виявляється:

ls -1 | xargs -I {} sh -c "grep ABC '{}' > '{}.out'"

Редагувати : одиничні цитати, додані після зауваження lhunath .


Він сказав, що хоче використовувати xargs. Я розмістив рішення і без нього, але видалив, як тільки побачив, що йому потрібні xargs.
Зіфре

Ти маєш рацію. Причиною, яку я опублікував, я відповів, що краще мати альтернативне рішення, щоб виконати роботу, ніж взагалі жодне. Виявляється, це поставило мене на правильний шлях, щоб знайти бажану відповідь (тобто, трюк sh -c).
Stephan202

14

Я припускаю, що ваш приклад - це лише приклад, який вам може знадобитися> для інших речей. GNU Parallel http://www.gnu.org/software/parallel/ може стати вашим порятунком. Для цього не потрібно додаткового цитування, доки ваші імена файлів не містять \ n:

ls | parallel "grep ABC {} > {}.out"

Якщо у вас є імена файлів із \ n:

find . -print0 | parallel -0 "grep ABC {} > {}.out"

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

Перегляньте вступні відео, щоб дізнатися більше: http://pi.dk/1

10-секундна установка спробує зробити повну установку; якщо це не вдається, персональна установка; якщо це не вдається, мінімальна установка:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 3374ec53bacb199b245af2dda86df6c9
12345678 3374ec53 bacb199b 245af2dd a86df6c9
$ md5sum install.sh | grep 029a9ac06e8b5bc6052eac57b2c3c9ca
029a9ac0 6e8b5bc6 052eac57 b2c3c9ca
$ sha512sum install.sh | grep f517006d9897747bed8a4694b1acba1b
40f53af6 9e20dae5 713ba06c f517006d 9897747b ed8a4694 b1acba1b 1464beb4
60055629 3f2356f3 3e9c4e3c 76e3f3af a9db4b32 bd33322b 975696fc e6b23cfb
$ bash install.sh

Якщо вам потрібно перемістити його на сервер, на якому не встановлено паралельну систему GNU, спробуйте parallel --embed.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.