Compter les fichiers dans un répertoire dont le nom de fichier correspond à une chaîne

La commande:

ls /some/path/some/dir/ | grep some_mask_*.txt | wc -l 

renvoie le nombre correct de fichiers lors de cette opération via ssh sur bash. Quand je mets ça dans un script .sh

 iFiles=`ls /some/path/some/dir/ | grep some_mask_*.txt | wc -l` echo "iFiles: ${iFiles}" 

c’est toujours 0 . Qu’est-ce qui ne va pas ici?

Solution:
Lorsque je travaillais dessus, j’ai découvert que mon “masque générique” semblait être le problème. using grep some_mask_ | grep \.txt grep some_mask_ | grep \.txt au lieu du grep unique ci-dessus m’a aidé à résoudre le problème pour le premier.

J’ai marqué la réponse comme une solution qui décrit à peu près exactement ce que je me suis trompé. Je vais éditer mon script maintenant. Merci tout le monde.

Le problème ici est que grep some_mask_*.txt est développé par le shell et non par grep, donc vous avez probablement un fichier dans le répertoire où grep est exécuté, correspondant à some_mask_*.txt et que grep utilise comme nom de fichier. filtre.

Si vous voulez vous assurer que le motif est utilisé par grep, vous devez le placer entre guillemets simples. En outre, vous devez écrire le modèle en tant qu’expression rationnelle et non en tant que correspondance générique (que bash utilise pour la correspondance). En mettant cela ensemble, votre version de ligne de commande devrait être:

 ls /some/path/some/dir/ | grep 'some_mask_.*\.txt' | wc -l 

et le script:

 iFiles=`ls /some/path/some/dir/ | grep 'some_mask_.*\.txt' | wc -l` echo "iFiles: ${iFiles}" 

Notez cela . doit être préfixé par une barre oblique inverse car elle a une signification particulière en tant qu’expression rationnelle correspondant à un seul caractère.

Je vous suggère également de postfixer l’expression rationnelle avec $ afin de l’ancrer à la fin (garantissant ainsi que l’expression rationnelle correspond aux noms de fichiers se terminant par “.txt”):

 ls /some/path/some/dir/ | grep 'some_mask_.*\.txt$' | wc -l 

Analyser ls n’est pas une bonne chose . Si vous voulez trouver des fichiers, utilisez find :

 find /some/path/some/dir/ -maxdepth 1 -name "some_mask_*.txt" -print0 

Cela imprimera les fichiers correspondant à la condition dans ce répertoire et sans entrer dans les sous-répertoires. Utiliser print0 évite les situations étranges lorsque le nom de fichier ne contient pas de caractères communs:

 -print0 True; print the full file name on the standard output, followed by a null character (instead of the newline character that -print uses). This allows file names that contain newlines or other types of white space to be correctly interpreted by pro‐ grams that process the find output. This option corresponds to the -0 option of xargs. 

Ensuite, passez simplement à wc -l pour obtenir le décompte final.


Au fait, notez que

 ls /some/path/some/dir/ | grep some_mask_*.txt 

peut être réduit à un simple

 ls /some/path/some/dir/some_mask_*.txt 

Je suggère d’utiliser find comme indiqué ci-dessous. La raison en est que les noms de fichiers peuvent contenir des nouvelles lignes qui pourraient casser un script utilisant wc -l . J’imprime juste un point par nom de fichier et compte les points avec wc -c :

 find /some/path/some/dir/ -maxdepth 1 -name 'some_mask_*.txt' -printf '.' | wc -c 

ou si vous voulez écrire les résultats dans une variable:

 ifiles=$(find /some/path/some/dir/ -maxdepth 1 -name 'some_mask_*.txt' -printf '.' | wc -c) 

Essaye ça,

 iFiles=$(ls /some/path/some/dir/ | grep some_mask_*.txt | wc -l) echo "iFiles: ${iFiles}" 

Je pense qu’il n’y aurait pas de problème de version shell.

essayez d’utiliser le caractère d’échappement sur votre commande. Il aime plus bas.

 ls /some/path/some/dir/ | grep some_mask_\*.txt | wc -l 

Votre problème est dû à l’ expansion du shell . Vous avez probablement testé la ligne de commande dans le répertoire d’origine, mais si vous l’essayez depuis un autre répertoire, cela ne fonctionnera plus.

Lorsque vous tapez:

 grep *.txt 

Ensuite, le shell remplace *.txt par tous les noms de fichiers correspondant au modèle puis exécute la commande (quelque chose comme grep a.txt dummy.txt ). Mais vous voulez que le pattern soit interprété par grep non développé par le shell, donc:

 ls /tmp | grep '.*.cpp' 

wille le faire. Ici, le modèle est dans la syntaxe de la commande grep (chaque commande en tant que sa propre syntaxe) et non développée car elle est protégée par des environnements.

Modifiez votre commande comme suit:

 a=`ls /tmp | grep '.*.cpp'` 

Ceci est assez similaire aux autres réponses, mais avec un peu plus de robustesse

 iFiles=$( find /some/path/ -name "some_mask_*.txt" -type f 2> /dev/null | wc -l ) echo "Number of files: $iFiles" 

Cela limite la recherche dans les fichiers et les canaux stderr à null, donc si la commande find ne fonctionne pas ou a des problèmes de permission, vous n’obtenez pas un résultat faux.