2010-09-22 17 views
1

Je cherche une commande qui trouve tous les fichiers dans un répertoire en utilisant un parter spécifique, disons "* .txt" et en crée une liste de paramètres dans BASH.Commande pour trouver tous les fichiers dans un répertoire et les concaténer pour un paramètre?

Donc, si le répertoire contient: file1.txt file2.txt file3.txt nonsense.c

J'ai besoin la chaîne "file1.txt file2.txt file3.txt"

I Je savais qu'il y avait une commande BASH/Unix pour cela, mais je ne m'en souviens pas: -S. "trouver" n'a pas fonctionné pour moi ...

Merci!

Yvan Janssens

Répondre

2

On dirait que vous voulez ls et xargs.

+0

xargs - c'était la commande que je cherchais ;-). Je pensais à un millier de commandes (pas vraiment, mais vous le savez), mais je ne pouvais pas me souvenir de cette minuscule ... – friedkiwi

0
$ echo "*.txt" 
1.txt 2.txt ... 
+1

Euh, non, si vous incluez les guillemets, vous obtiendrez juste l'impression '* .txt' . –

+0

Eh bien, il y a de meilleures réponses maintenant de toute façon :) – LukeN

1

Vous avez demandé l'une des fonctionnalités les plus basiques de n'importe quel shell Unix. C'est connu sous le nom de "globbing", pour une raison quelconque, et il est intégré.

$ echo *.txt 
0

Si vous êtes à la recherche de fichiers dans un répertoire, pas dans les répertoires imbriqués, vous pouvez utiliser un argument glob à votre commande, qui sera interprété par le shell et produire un argument à votre commande pour chaque correspondance nom:

$ echo *.txt 
file1.txt file2.txt file3.txt 

Si vous cherchez des fichiers imbriqués arbitrairement profondément dans les sous-répertoires, find est en effet ce que vous recherchez. Vous devez passer dans le répertoire que vous recherchez, et utiliser le paramètre -name avec une expression glob citée pour trouver les fichiers appropriés (si le glob n'est pas cité, le shell essayera de l'interpréter, et substituera une liste de fichiers correspondants ce nom dans le répertoire courant, ce qui est ce que vous voulez):

$ find . -name "*.txt" 
file1.txt. file2.txt file3.txt subdir/file.txt 

Si vous voulez passer ceux-ci comme arguments à une autre fonction, vous pouvez utiliser $() (ce qui équivaut aux backquotes plus familiers ``) ,

echo $(find . -name "*.txt") 

Ou si vous allez obtenir une liste trop longue f Vous pouvez utiliser xargs, qui divise son entrée en blocs, chacun étant suffisamment petit pour être transmis à une commande.

find . -name "*.txt" | xargs echo 

Si vos noms de fichiers contiennent des espaces, puis xargs va les diviser en deux morceaux, traiter chacun comme un argument séparé, ce qui est pas ce que vous voulez. Vous pouvez éviter cela en utilisant le caractère nul, 0, en tant que délimiteur, avec l'argument -print0 à find et l'argument -0 à xargs.

find . -name "*.txt" -print0 | xargs -0 echo 
3

Si vous voulez exécuter une commande sur les fichiers correspondants par un caractère générique, vous n'avez pas besoin de bagages supplémentaires:

mycommand *.txt 

Qu'est-ce que vous vous souvenez probablement la commande xargs. Il prend une liste de noms de fichiers sur son entrée standard, et exécute une commande sur ces fichiers. Par exemple echo *.txt | xargs mycommand est un complexe, et peu fiable, façon d'écrire mycommand *.txt. xargs est utile lorsque la liste des fichiers sur lesquels doit agir mycommand est la sortie d'une autre commande.

La raison pour laquelle je l'ai dit xargs est peu fiable est qu'il attend son entrée à rappeler d'une façon particulière: tous les espaces (pas seulement des sauts de ligne) noms séparés, antislashs doivent être doublés, et ' et " délimitent les chaînes littérales (dans lequel seulement backslash et la fin de citation sont spéciaux). Comme peu de commandes produisent une sortie au format d'entrée xargs, cela limite l'utilité de xargs aux rares cas où l'on sait que les noms de fichiers ne contiendront aucun des caractères spéciaux.

La commande find est souvent utilisée en combinaison avec xargs, mais cela devrait et peut être évité. Au lieu de find ... | xargs mycommand , écrivez

find ... -exec mycommand {} + 
+0

xargs a le drapeau '-0' pour résoudre la plupart (tous?) De ces problèmes. –

+0

@Carl: 'xargs -0' corrige les problèmes de citations, mais n'est pas disponible partout (seulement GNU et (certains?) BSD), et nécessite que l'entrée soit séparée par zéro, ce que peu de commandes peuvent produire. – Gilles

2

La réponse est simple

mylist=$(ls *.txt) 

NOTE: ls signale une erreur si rien ne correspond. Les erreurs peuvent être redirigées vers/dev/null.

Pour les commandes autres que ls et find, s'il n'y a pas de correspondance, l'utilisation générique renvoie généralement le caractère générique comme résultat; il est donc nécessaire de gérer le cas particulier de non-correspondance.

Ce qui suit définit la variable "list" pour tous les fichiers .txt ou la définit comme chaîne vide si aucun fichier de ce type n'existe. L'avantage par rapport à ls (1) est que si vous n'appelez aucune commande externe.

list=$(echo *.txt) 
if [ "$list" = "*.txt" ] ; then list=""; fi 

Exemple d'utilisation pour exécuter ma commande, mais seulement si la liste n'est pas vide:

test -n "$list" && my-command $list 

Maintenant, si vos fichiers peuvent avoir des espaces dans leur nom, puis un tableau est mieux:

List=() 
let n=0 
for x in *.txt 
do 
    test -e "$x" || exit 
    List[n++]="$x" 
done 

utilisez ensuite la liste avec

test ${#List[@]} -gt 0 && my-command "${List[@]}" 

ou

for value in "$List[@]" ; do my-command "$value" ; done 

Tout cela est peut-être un peu différent pour ksh, mais il serait très similaire.