Я пытаюсь наивно
$ cat * | sort -u > /tmp/bla.txt
который терпит неудачу с:
-bash: /bin/cat: Argument list too long
Таким образом, чтобы избежать глупого решения типа (создает огромный временный файл):
$ find . -type f -exec cat {} >> /tmp/unsorted.txt \;
$ cat /tmp/unsorted.txt | sort -u > /tmp/bla.txt
Хотя я мог обрабатывать файлы один за другим (это должно уменьшить потребление памяти и быть ближе к потоковому механизму):
$ cat proc.sh
#!/bin/sh
old=/tmp/old.txt
tmp=/tmp/tmp.txt
cat $old "$1" | sort -u > $tmp
mv $tmp $old
Затем следует:
$ touch /tmp/old.txt
$ find . -type f -exec /tmp/proc.sh {} \;
Есть ли более простая замена в стиле Unix для: cat * | sort -u
когда количество файлов достигнет MAX_ARG
? Нелегко писать небольшой скрипт для такой распространенной задачи.
sort
делает это автоматически для ввода нескольких файлов ... но тогдаsort -u *
,Argument list too long
я полагаю, тоже потерпел бы неудачуОтветы:
С GNU
sort
иprintf
встроенной оболочкой (в настоящее время все POSIX-подобные, кроме некоторых вариантовpdksh
):Теперь проблема в том, что, поскольку два компонента этого конвейера запускаются одновременно и независимо, к тому времени, когда левый расширяет
*
глобус, правый может уже создатьoutput
файл, который может вызвать проблемы (возможно, не-u
здесь) Какoutput
и входной, и выходной файл, вы можете захотеть, чтобы выходные данные перешли в другой каталог (> ../output
например), или убедитесь, что глобус не соответствует выходному файлу.Другой способ решения этой проблемы в этом случае - написать:
Таким образом, он
sort
открываетсяoutput
для записи и (в моих тестах) не будет делать этого, пока не получит полный список файлов (так долго после того, как глобус будет расширен). Это также позволит избежать дублирования,output
если ни один из входных файлов не будет читаемым.Другой способ написать это с помощью
zsh
илиbash
При этом используется подстановка процесса (где
<(...)
заменяется путь к файлу, который относится к концу чтения канала, в которыйprintf
производится запись). Эта функция взятаksh
, ноksh
требует расширения<(...)
отдельного аргумента для команды, чтобы вы не могли использовать его с--option=<(...)
синтаксисом. Это будет работать с этим синтаксисом, хотя:Обратите внимание, что вы увидите отличие от подходов, которые
cat
передают вывод файлов, в тех случаях, когда есть файлы, которые не заканчиваются символом новой строки:Также обратите внимание, что
sort
сортирует, используя алгоритм сортировки в locale (strcollate()
), иsort -u
сообщает одну из каждого набора строк, которые сортируются по этому алгоритму, а не уникальные строки на уровне байтов. Если вы заботитесь только об уникальности строк на уровне байтов и не заботитесь о порядке их сортировки, возможно, вы захотите зафиксировать локаль в C, где сортировка основана на значениях байтов (memcmp()
; это, вероятно, ускорит дела обстоят значительно):источник
sort
оптимизировать потребление памяти. Я все еще нахожуprintf '%s\0' *
немного сложным для ввода, хотя.find . -type f -maxdepth 1 -print0
вместоprintf '%s\0' *
, но я не могу утверждать, что это легче набрать. И последний, конечно, легче определить как псевдоним!echo
имеет-n
, я бы предпочел что-то вродеprintf -0 %s
этого, кажется, немного менее низкий уровень, чем'%s\0'
-maxdepth
и-print0
являются расширениями GNU (хотя и широко поддерживаются в наши дни). С другимиfind
s (хотя если у вас есть сортировка GNU, вы, вероятно, также найдете GNU), вы можете это сделатьLC_ALL=C find . ! -name . -prune -type f ! -name '.*' -exec printf '%s\0' {} +
(LC_ALL=C
по-прежнему исключая скрытые файлы, содержащие недопустимые символы, даже с GNUfind
), но это немного излишне, когда вы обычно естьprintf
встроенный.print0
функцию какprint0() { [ "$#" -eq 0 ] || printf '%s\0' "$@";}
и тогдаprint0 * | sort...
Простое исправление работает, по крайней мере, в Bash, поскольку
printf
встроено, и ограничения аргументов командной строки к нему не применяются:(
echo * | xargs
также будет работать, за исключением обработки имен файлов с пробелами и т. д.)источник
cat
процесса для каждого файла.find -exec {} +
объединяет несколько файлов за одно выполнение. Сfind -exec \;
ним будет один кот на файл.Это объединит все не скрытые обычные файлы в текущем каталоге и отсортирует их объединенное содержимое (при удалении дублированных строк) в файл
/path/to/sorted.txt
.источник
|
, правильно ли будут цепочки операций для ограничения использования памяти?sort
будет выполнять сортировку вне ядра, если этого требуют требования памяти. По сравнению с ним левая сторона конвейера потребляет очень мало памяти.Эффективность - это относительный термин, поэтому вам действительно нужно указать, какой фактор вы хотите минимизировать; Процессор, память, диск, время и т. д. В качестве аргумента я собираюсь предположить, что вы хотели минимизировать использование памяти и готовы потратить больше циклов процессора для достижения этой цели. Решения, подобные предложенным Стефаном Шазеласом, хорошо работают
но они предполагают, что отдельные текстовые файлы имеют высокую степень уникальности для начала. Если нет, то есть, если после
sample.srt более чем на 10% меньше, чем sample.txt, тогда вы сэкономите значительную память, удалив дубликаты в файлах перед объединением. Вы также сэкономите еще больше памяти, не цепляя команды, а это значит, что результаты разных процессов не обязательно должны быть в памяти одновременно.
источник
sort
какsort
прибегает к использованию временных файлов, когда использование памяти превышает пороговое значение (обычно относительно небольшое).base64 /dev/urandom | sort -u
заполнит ваш диск, но не займет много памяти.sort
реализаций, включая оригинальную в Unix v3 в 1972 году, но, видимо, нетbusybox sort
. Предположительно потому, что он предназначен для работы в небольших системах, которые не имеют постоянного хранилища.yes | sort -u
(все дублированные данные) не должны использовать больше, чем несколько байтов памяти, не говоря уже о диске. Но,sort
по крайней мере, с GNU и Solaris мы видим, что он записывает много 2-байтовых больших файлов/tmp
(y\n
на каждые несколько мегабайт ввода), так что в конечном итоге он заполнит диск.Вроде @ilkkachu, но cat (1) не нужен:
Кроме того, если данные слишком длинные, возможно, вы захотите использовать опцию sort (1) --parallel = N
Когда N - это количество процессоров, которые есть у вашего компьютера
источник