xargs w c -l сообщает о двух итогах - PullRequest
0 голосов
/ 05 апреля 2020

Я хочу вычислить все строки в каталоге /usr/local/lib/python3.5/dist-packages/pandas.

cd /usr/local/lib/python3.5/dist-packages/pandas
find  -name '*.*' |xargs  wc -l
536577 total

Запишите две строки как одну строку.

 find  /usr/local/lib/python3.5/dist-packages/pandas  -name '*.*' |xargs wc -l    

enter image description here

bash вывести два total числа, одно 495736, другое 40841,

495736 + 40841 = 536577

Почему bash не дают только одну сумму 536577 внизу, например find -name '*.*' |xargs wc -l до?

Ответы [ 2 ]

4 голосов
/ 05 апреля 2020

POSIX xargs spe c. говорит:

Сгенерированная длина командной строки должна быть суммой размера в байтах имени утилиты, и каждый аргумент рассматривается как строки, включая нулевой байт-терминатор для каждой из этих строк. Утилита xargs должна ограничивать длину командной строки, чтобы при вызове командной строки комбинированные списки аргументов и среды не превышали {ARG_MAX}-2048 байтов.

Это означает; в вашем случае вывод find не помещается в ARG_MAX ‒ 2048 байт, поэтому xargs объединяет его в 2 набора и вызывает w c один раз для каждого набора.


Возьмем этот конвейер, например, в в идеальном мире его вывод будет 1, но это не так.

seq 1000000 | xargs echo | wc -l

вывод seq - 6888896 байт.

$ seq 1000000 | wc -c
6888896

Мой список окружений занимает 558 байт ( игнорирование того, что _ является динамическим c и учитывает ли реализация для ясности завершающие нулевые указатели).

$ env | wc -c
558

ARG_MAX в моей системе составляет 131072 байта.

$ getconf ARG_MAX
131072

Теперь xargs имеет 131072‒2048‒558 = 128466 байт; echo плюс нулевой разделитель занимает 5 байтов, поэтому остается пространство 128461 байта. Поэтому можно сказать, что xargs придется вызывать echo 6888896/128461 = ~ 54 раза. Давайте посмотрим, так ли это:

$ seq 1000000 | xargs echo | wc -l
54

Да, это так.

0 голосов
/ 05 апреля 2020

Вы можете справиться с xargs многократным выполнением команды, добавив бит awk в конвейер:

find wherever -name "*.*" -type f -print0 | \
xargs -0 wc -l | \
awk '$2 == "total" { total += $1 } END { print "Overall total", total } 1'

(Предполагая GNU find и xargs или другие реализации, которые понимают -print0 и -0 соответственно, в противном случае имена файлов с пробелами et c. Могут вызывать проблемы).

GNU find и, возможно, другие реализации могут пропустить xargs, фактически:

find wherever -name "*.*" -type f -exec wc -l '{}' '+'

будет иметь тот же эффект, что и использование xargs для запуска wc одновременно для нескольких файлов.

...