Не понимаете перенаправления в этой команде? [дубликат]

С GNU sort и оболочкой, в которую встроен printf (в настоящее время все POSIX-подобные, за исключением некоторых вариантов pdksh ):

printf '%s\0' * | sort -u --files0-from=- > output

Теперь проблема заключается в том, что, поскольку два компонента этого конвейера выполняются одновременно и независимо, к тому времени, когда левый расширяет глобус *, правый может уже создали файл output, который может вызвать проблемы (возможно, не с -u здесь), поскольку output будет и входным, и выходным файлом, так что вы можете хотите, чтобы вывод перешел в другой каталог (например, > ../output), или убедитесь, что glob не соответствует выходному файлу.

Другой способ обратиться к этому экземпляру — написать его:

printf '%s\0' * | sort -u --files0-from=- -o output

Таким образом, он сортирует открывает выход для записи и (в моих тестах) Не делайте этого до того, как он получит полный список файлов (так долго после того, как глобус был расширен). Это также позволит избежать затирания вывода , если ни один из входных файлов не читается.

Другой способ записать это с помощью zsh или bash

sort -u --files0-from=<(printf '%s\0' *) -o output

Это использование подстановки процесса (где <(...) заменяется путем к файлу, который ссылается к считывающему концу канала printf для записи). Эта функция происходит от ksh, но ksh настаивает на том, чтобы сделать расширение <(...) отдельным аргументом команды, поэтому вы не можете использовать это с опцией --option=<(...) синтаксис. Это будет работать с этим синтаксисом:

sort -u --files0-from <(printf '%s\0' *) -o output

Обратите внимание, что вы увидите разницу с подходами, которые передают вывод cat в файлы в случаях, когда есть файлы, которые не заканчиваются новой строкой. символ:

$ printf a > a
$ printf b > b
$ printf '%s\0' a b | sort -u --files0-from=-
a
b
$ printf '%s\0' a b | xargs -r0 cat | sort -u
ab

Также обратите внимание, что sort сортирует с использованием алгоритма сопоставления в локали (strcollate()), а sort -u сообщает об одном из каждого набора строк, которые сортируются одинаково по этому алгоритму, а не уникальные строки на уровне байтов. Если вы заботитесь только об уникальности строк на уровне байтов и не слишком заботитесь о порядке их сортировки, вы можете захотеть исправить языковой стандарт на C, где сортировка основана на байтовых значениях (memcmp( ); это, вероятно, значительно ускорит процесс):

printf '%s\0' * | LC_ALL=C sort -u --files0-from=- -o output
0
10.07.2017, 13:59
1 ответ

Чтобы попытаться объяснить более буквально, чем великий теоретический ответ meuh -, как вы, вероятно, знаете, существует ряд файловых дескрипторов по умолчанию:

  • 0означает стандартный ввод
  • 1означает стандартный вывод
  • 2означает stderr

Ваша команда делает следующее:

  • 3>allоткрыть новый файловый дескриптор, указывающий на файлall
  • 1> >(tee out >&3)перенаправить стандартный вывод(1)на файловый дескриптор, открытый и возвращенный командой tee, как объяснил meuh
    • tee out >&3перенаправляет свой ввод (, в данном случае стандартный вывод из вашего скрипта )в файл с именем out, и везде, где файловый дескриптор 3указывает на (, в этом случае файл all)
  • 2> >(tee err >&3)перенаправить stderr(2)на дескриптор файла, открытый и возвращенный командой tee, как объяснил meuh
    • tee err >&3перенаправляет свой ввод (, в данном случае stderr из вашего скрипта )в файл с именем err,и везде, где дескриптор файла 3указывает на (, в этом случае файл все)

Судя по вашему комментарию, я думаю, что вас смущает то, что вы ожидаете, что вам нужно будет использовать >>в качестве оператора перенаправления, если вы хотите добавить вывод в файл.

Здесь дело обстоит иначе, так как все, что вы буквально делаете, это подключаете и stdout, и stderr к файловому дескриптору, который указывает на файл all.

Эффект тот же, что и при выполнении:

./my.sh > all 2>&1

Что сначала перенаправляет stdout в файл all, а затем перенаправляет stderr туда, куда указывает stdout.

2
28.01.2020, 02:15

Теги

Похожие вопросы