Я изучал командную строку и узнал, что |
(конвейер) предназначен для перенаправления вывода команды на ввод другой. Так почему же команда ls | file
не работает?
file
вход является одним из нескольких имен файлов, таких как file filename1 filename2
ls
Вывод - это список каталогов и файлов в папке, поэтому я подумал, что ls | file
должен показывать тип файла для каждого файла в папке.
Когда я использую его, однако, вывод:
Usage: file [-bcEhikLlNnprsvz0] [--apple] [--mime-encoding] [--mime-type]
[-e testname] [-F separator] [-f namefile] [-m magicfiles] file ...
file -C [-m magicfiles]
file [--help]
Так как произошла какая-то ошибка при использовании file
команды
ls
, это означает, что вы хотите, чтобы все файлы в текущем каталоге обрабатывалисьfile
командой. ... Так почему бы просто не сделать:,file *
который будет отвечать строкой для каждого файла, папки.file *
это самый умный способ, мне просто интересно, почему использованиеls
вывода не работает. Сомнение прояснилось :)ls
вообще плохая идея.Ответы:
Основная проблема заключается в том,
file
что имена файлов ожидаются в качестве аргументов командной строки, а не в stdin. Когда вы пишете,ls | file
выводls
передается в качестве вводаfile
. Не в качестве аргументов, а в качестве входных данных.Какая разница?
Аргументы командной строки - это когда вы пишете флаги и имена файлов после команды, как в
cmd arg1 arg2 arg3
. В скриптах эти аргументы доступны как переменный$1
,$2
,$3
и т.д. В C вы бы получить доступ к их черезchar **argv
иint argc
аргументыmain()
.Стандартный ввод, stdin, представляет собой поток данных. Некоторые программы любят
cat
илиwc
читают из stdin, когда им не дают никаких аргументов командной строки. В сценарии оболочки вы можете использовать,read
чтобы получить одну строку ввода. В C вы можете использоватьscanf()
илиgetchar()
, среди различных вариантов.file
обычно не читает со стандартного ввода. Ожидается, что в качестве аргумента будет передано хотя бы одно имя файла. Вот почему он печатает использование, когда вы пишетеls | file
, потому что вы не передали аргумент.Вы можете использовать
xargs
для преобразования stdin в аргументы, как вls | xargs file
. Тем не менее, как отмечает Тердон , разборls
- плохая идея. Самый прямой способ сделать это просто:источник
file
получать имена файлов из его ввода, используяls | file -f -
. Все еще плохая идея.ls
выводятся в стандартныйfile
ввод. Попробуйте это.file $(ls)
, что также работает, еще одним способом.Потому что, как вы говорите, ввод
file
должен быть именами файлов . Выводls
, однако, просто текст. То, что это список имен файлов, не меняет того факта, что это просто текст, а не расположение файлов на жестком диске.Когда вы видите результат печати на экране, вы видите текст. Является ли этот текст стихотворением или списком имен файлов, для компьютера не имеет значения. Все, что он знает, это то, что это текст. Вот почему вы можете передавать выходные данные
ls
программам, которые принимают текст в качестве входных данных (хотя вы действительно, действительно, не должны ):Таким образом, чтобы использовать выходные данные команды, которая перечисляет имена файлов в виде текста (например,
ls
илиfind
), в качестве входных данных для команды, которая принимает имена файлов, вам необходимо использовать некоторые приемы. Типичный инструмент для этогоxargs
:Как я уже говорил ранее, вы действительно не хотите анализировать вывод
ls
. Что - то вродеfind
лучше (тоprint0
печатает\0
вместо того , newilne после каждого имени файла и-0
изxargs
позволяет ему иметь дело с таким входом, это уловка , чтобы сделать ваши команды работают с именами файлов , содержащих символы новой строки):Который также имеет свой собственный способ сделать это, без необходимости
xargs
вообще:Наконец, вы также можете использовать цикл оболочки. Однако учтите, что в большинстве случаев
xargs
будет намного быстрее и эффективнее. Например:источник
file
не появляется на самом деле читать стандартный ввод , если не дано явное-
заполнителем: сравнитьfile foo
,echo foo | file
иecho foo | file -
; на самом деле это, вероятно, и является причиной сообщения об использовании в случае OP (то есть, на самом деле это не потому, что выводls
«просто текст», а скорее потому, что список аргументов дляfile
пуст)echo foo | file -
самом деле он запускается неfile
в файле,foo
а в потоке stdin.cat
это, за исключением stdin без,-
кроме случаев, когда даются аргументы файла, я думаю?Он не «перенаправляет» выходные данные, но принимает выходные данные программы и использует их в качестве входных данных, в то время как файл не принимает входные данные, а имена файлов в качестве аргументов , которые затем проверяются. Перенаправления не передают эти имена файлов в качестве аргументов , как это делает ни конвейер , чем позже вы делаете.
Что вы можете сделать, это прочитать имена файлов из файла с
--files-from
опцией, если у вас есть файл, в котором перечислены все файлы, которые вы хотите проверить, в противном случае просто укажите пути к вашим файлам в качестве аргументов.источник
Принятый ответ объясняет, почему команда pipe не работает сразу, и с помощью
file *
команды она предлагает простое и прямое решение.Я хотел бы предложить другую альтернативу, которая может пригодиться в какое-то время. Хитрость заключается в использовании
(`)
символа обратного хода . Обратный удар объясняется очень подробно здесь . Короче говоря, он принимает выходные данные команды, заключенные в обратные кавычки, и подставляет их в виде строки в оставшуюся команду.Итак,
find `ls`
возьмем выводls
команды и подставим его в качестве аргументовfind
команды. Это длиннее и сложнее, чем принятое решение, но варианты этого могут быть полезны в других ситуациях.источник
command
(не могу найти код обратной косой черты в моем телефоне), чтобы расширить вывод команды в bash и использовать ее в качестве параметра для других команд. Действительно полезно, даже если его использование в этом случае (с ls ) все равно приведет к некоторым проблемам из-за специальных символов в некоторых именах файлов.Вывод
ls
через канал представляет собой сплошной блок данных с 0x0a, разделяющим каждую строку - то есть символ перевода строки - иfile
получает это как один параметр, где он ожидает, что несколько символов будут работать с одним за раз.Как правило, никогда не используйте
ls
для генерации источника данных для других команд - однажды он будет передан по трубопроводу ...rm
и тогда у вас проблемы!Лучше использовать цикл, например,
for i in *; do file "$i" ; done
который будет производить желаемый результат, как и ожидалось. Кавычки есть в случае имен файлов с пробелами.источник
file *
;-)ls
- очень, очень плохая идея . Не только потому, что вы можете передать это чему-то вредному, напримерrm
, что более важно, потому что оно ломается от любого нестандартного имени файла.rm
имена файлов из стандартного ввода? Думаю, нет. Кроме того, как общее правило,ls
был одним из основных примеров источника данных для использования конвейеров Unix с самого начала Unix. Вот почему по умолчанию он представляет собой простое имя файла на строку без атрибутов или украшений, когда его вывод представляет собой канал, в отличие от его обычного форматирования по умолчанию, когда вывод представляет собой терминал.Если вы хотите использовать канал для подачи,
file
используйте опцию, за-f
которой обычно следует имя файла, но вы также можете использовать один дефис-
для чтения из stdin, поэтомуТрюк с дефисом
-
работает со многими стандартными утилитами командной строки (хотя--
иногда это так), поэтому его всегда стоит попробовать.Этот инструмент
xarg
гораздо более мощный и в большинстве случаев необходим только в том случае, если список аргументов слишком длинный (подробности см. В этом посте ).источник
--
? Я никогда этого не видел.--
обычно это индикатор «конца флагов».Это работает использовать команду, как показано ниже
Это будет работать лучше для меня
источник
Это также должно работать:
как также обсуждалось здесь: https://unix.stackexchange.com/questions/5778/whats-the-difference-between-stuff-and-stuff
источник
$()
метод такой же, как метод обратного