Передача вывода «find» в «xargs wc» дает необоснованные итоги

Передача вывода «find» в «xargs wc» дает необоснованные итоги

В проекте с тысячами файлов мне захотелось сравнить общее количество строк кода со строками кода только на PHP (без учета CSS, JavaScript и т. д.).

Когда я бегу

find . -type f | xargs wc -l

итог в последней строке равеннижечем когда я бегу

find -E . -regex '.+\.(php|inc)' -type f | xargs wc -l

Учитывая, что второй findсписок файлов должен быть меньше первого (является его строгим подмножеством) find, как можно было бы wcсообщить о большем общем количестве во втором случае?

решение1

xargsможет только пройти ARG_MAXбайты аргументов в wc.

На моем Mac ARG_MAX меньше, чем полные имена файлов и относительные пути всех файлов проекта, поэтому впервыйкоманда, сбросила xargsрезультатыfindwc в двух партиях, что означало, что wcпотушитьдва итога, окруженный тысячами имен файлов. Но ARG_MAX оказался больше, чемвторой findвыход, поэтому второй, меньший результат поиска показал всеодин wcобщий.

Исправление заключалось в использовании этих команд, чтобы я мог видеть все итоговые данные без (скучных) строк с количеством отдельных файлов:

find . -type f | xargs wc -l | grep total
find -E . -regex '.+\.(php|inc)' -type f | xargs wc -l | grep total

Затем вручную просуммируйте несколько строк «итого».

решение2

Есть много способов сделать это, и xargsэто не лучший из них. Вот несколько:

  1. Самый простой, это для catкаждого из найденных файлов findи подсчет строк. Осторожно, это работает только если имена ваших файлов не содержат пробелов или странных символов:

    find . -type f | while read n; do cat $n; done | wc -l
    find -E . -regex '.+\.(php|inc)' -type f | while read n; do cat $n; done | wc -l 
    

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

    find . -type f | while IFS= read -r n; do cat $n; done | wc -l
    find -E . -regex '.+\.(php|inc)' -type f | while IFS= read -r n; do cat $n; done | wc -l 
    
  2. Лучший способ — использовать -execопцию find:

    find . -name "*.pep" -exec cat {} \; | wc
    find -E . -regex '.+\.(php|inc)' -type f -exec cat {} \; | wc
    

решение3

Используйте awkдля суммирования различных «общих» чисел выходов wc -l!

(Примечание: wc -lвозвращает количество символов новой строки, т.е. конечные «строки» без конечного \nсимвола не будут учитываться — как в случае с awkили sed.)

export LC_ALL=C
find . -type f -print0 | xargs -0 wc -l | 
    awk '/^ *[[:digit:]]+ total$/{ total+=$1 }END{print total}'


# xargs alternatives using: find ... -exec <wc|awk|sed> ... '{}' +
#man find | less -p '{} \+'

# wc
find . -type f -exec wc -l '{}' + 2>/dev/null | 
   awk '/^ *[[:digit:]]+ total$/{ total+=$1 }END{print total}'

# awk
find . -type f -exec awk 'END {print NR}' '{}' + 2>/dev/null | 
    awk '{ total+=$1 }END{print total}'

# sed
find . -type f -exec sed -n '$=' '{}' + 2>/dev/null | 
    awk '{ total+=$1 }END{print total}'

Связанный контент