La sortie de tuyauterie de 'find' à 'xargs wc' donne des totaux déraisonnables

0

Dans un projet avec des milliers de fichiers, je voulais comparer les lignes de code totales aux lignes de code uniquement en PHP (suppression de CSS, JavaScript, etc.)

Quand je cours

find . -type f | xargs wc -l

le total sur la dernière ligne est inférieur que quand je cours

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

Considérant le second find doit être une liste de fichiers plus petite que (est un sous-ensemble strict) du premier find, comment pourriez wc signaler un total plus élevé dans le second cas?

Jeremy Wadhams
la source

Réponses:

1

xargs ne peut que passer ARG_MAX octets d'arguments à wc.

Sur mon Mac, ARG_MAX est plus petit que les noms de fichiers complets et les chemins relatifs des fichiers du projet entier. premier commander, xargs jeté les résultats de la find à wc en deux lots , ce qui signifie que wc éteindre deux totaux , entouré de milliers de noms de fichiers. Mais ARG_MAX s'est avéré être plus grand que le seconde find sortie, donc la deuxième, plus petite découverte tout montré dans un wc total.

Le correctif consistait à utiliser ces commandes afin que je puisse voir tous les totaux sans les lignes (ennuyeuses) du nombre de fichiers individuels:

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

Puis additionnez les plusieurs "totaux" à la main.

Jeremy Wadhams
la source
Ou faire find . -type f | xargs cat | wc -l
Alan Shutko
0

Il y a plusieurs façons de le faire et xargs n'est pas le meilleur. Voici un couple:

  1. Le plus simple, est de cat chacun des fichiers trouvés par find et compter les lignes. Attention, cela ne fonctionne que pour vos noms de fichiers sans espaces ni caractères étranges

    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 
    

    Si vos noms de fichiers sont susceptibles de contenir des caractères étranges (barres obliques, espaces, etc.), utilisez ceci à la place:

    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. Un meilleur moyen est d'utiliser find -exec option:

    find . -name "*.pep" -exec cat {} \; | wc
    find -E . -regex '.+\.(php|inc)' -type f -exec cat {} \; | wc
    
terdon
la source
Le problème réel de Jeremy étant qu’il avait trop de noms de fichiers pour tenir sur une ligne de commande, votre première approche a peu de chances de fonctionner.
Scott
@ Scott Yup, bon point, réponse mise à jour.
terdon
Pouvez même IFS= read –r n gérer les noms de fichiers contenant des nouvelles lignes? Peut-être que la solution idéale est un hybride: find … –print0 | xargs –0 cat | wc.
Scott
Darn it @Scott, bon point encore :). je pensée qu’il pouvait gérer les nouvelles lignes en raison d’un commentaire d’un utilisateur très expérimenté d’UL.SE qui, je me rends bien compte, j’ai mal compris. -print0 échoue également sur les nouvelles lignes. J'ai supprimé la référence aux nouvelles lignes pour éviter toute confusion.
terdon
1
Oui, mais ce n’est pas ce que j’ai suggéré. le –0 option de xargs et le –print0 prédicat de find ont été conçus pour fonctionner main dans la main.
Scott
0

Utilisation awk résumer les différents nombres "totaux" du wc -l les sorties!

(Remarque: wc -l renvoie le nombre de caractères de nouvelle ligne, i. e. "lignes" finales sans finale \n caractère ne sera pas compté - comme c'est le cas avec awk ou 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}'
cahn
la source