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


18

За визначенням людини, ця команда отримує вхід з файлу.

$ command -r FILENAME

Припустимо , що FILENAMEце файл , який містить список імен файлів, так як він був створений з використанням ls > FILENAME.

Як я можу натомість подати команду результатом lsбезпосередньо? У моїй голові має бути можливо щось подібне:

$ ls | command -r

Але це не так, висновок lsне сприймається як аргумент. Вихід:

Usage: command -r FILENAME
error: -r option requires an argument

Як я міг отримати бажаний ефект?


Інші відповіді на це в суміжний питання: Як передати рядок в команді, яка чекає на файл?
ilkkachu

Відповіді:


32

Це залежить від команди. Деякі команди, що читаються з файлу, очікують, що файл буде звичайним файлом, розмір якого відомий заздалегідь, і який можна прочитати з будь-якої позиції та перемотати назад. Це малоймовірно, якщо вміст файлу - це список імен файлів: тоді команда, ймовірно, буде вміщуватись з трубою, яку вона просто читатиме послідовно від початку до кінця. Існує декілька способів подачі даних через трубу до команди, яка очікує імені файлу.

  • Багато команд трактують -як спеціальне ім'я, тобто читати зі стандартного введення, а не відкривати файл. Це конвенція, а не зобов'язання.

    ls | command -r -
  • Багато варіантів Unix надають спеціальні файли, /devщо позначають стандартні дескриптори. Якщо /dev/stdinіснує, відкриття та читання з нього еквівалентно читанню зі стандартного вводу; так само, /dev/fd/0якщо вона існує.

    ls | command -r /dev/stdin
    ls | command -r /dev/fd/0
  • Якщо ваша оболонка - ksh, bash або zsh, ви можете змусити вирішити справу з виділенням дескриптора файлу. Основна перевага цього методу полягає в тому, що він не прив’язаний до стандартного вводу, тому ви можете використовувати стандартний вхід для чогось іншого, і ви можете використовувати його не один раз.

    command -r <(ls)
  • Якщо команда очікує, що ім'я має певну форму (як правило, певне розширення), ви можете спробувати обдурити його символічним посиланням.

    ln -s /dev/fd/0 list.foo
    ls | command -r list.foo

    Або ви можете використовувати названу трубу.

    mkfifo list.foo
    ls >list.foo &
    command -r list.foo

Зауважте, що створити список файлів за допомогою lsпроблематично, тому що, lsяк правило, маніпулювати назви файлів, коли вони містять символи, що не можна друкувати. printf '%s\n' *надійніше - він буде друкувати кожен байт буквально у назвах файлів. Імена файлів, що містять нові рядки, все ще спричинять проблеми, але це неминуче, якщо команда очікує списку імен файлів, розділених новими рядками.


+1 для перерахування всіх можливостей. Заміна процесу ІМО є правильною відповіддю для цієї ситуації.
glenn jackman

7

Вона повинна бути:

ls | xargs -n 1 command -r

Редагувати: для імен з порожніми пробілами:

ls | xargs -d '\n' -n 1 command -r

Це може бути проблематично, якщо commandвін вважає, що він має всі імена файлів, які знадобляться в командному рядку відразу. Деякі версії xargs дадуть commandодночасно декілька імен файлів (10, як мені здається). Схоже, xargs GNU дає все одразу.
Брюс Едігер

2

Насправді, єдине надійне рішення, яке мені відомо, що може обробляти всі імена файлів, у тому числі й ті, у яких є новий рядок:

find . -maxdepth 1 -print0 | xargs -n 1 -0 command -r

Єдиний недозволений символ у назви файлу в цьому випадку - це нульовий символ, який у будь-якому випадку заборонений у назви файлів.


1

Багато команд приймають -як "ім'я файлу", що означає "використовувати стандартний ввід", але ця умова далеко не універсальна. Прочитайте сторінку чоловіка.


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