Quelqu'un pourrait-il fournir le code pour effectuer les opérations suivantes: Supposons qu'il existe un répertoire de fichiers, qui doivent tous être exécutés via un programme. Le programme sort les résultats en sortie standard. J'ai besoin d'un script qui ira dans un répertoire, exécutera la commande sur chaque fichier et concaténera la sortie dans un gros fichier de sortie.
Par exemple, pour exécuter la commande sur 1 fichier:
$ cmd [option] [filename] > results.out
ls <directory> | xargs cmd [options] {filenames put in here automatically by xargs} [more arguments] > results.out
ls
probablement pas l'utiliser pour conduirexargs
. Sicmd
c'est écrit avec compétence, vous pouvez peut-être simplement le fairecmd <wildcard>
.Réponses:
Le code bash suivant passera $ file à la commande où $ file représentera chaque fichier dans / dir
Exemple
la source
/dir/
, la boucle s'exécute toujours une fois avec une valeur de '*' pour$file
, ce qui peut être indésirable. Pour éviter cela, activez nullglob pendant la durée de la boucle. Ajoutez cette ligne avant la boucleshopt -s nullglob
et cette ligne après la boucleshopt -u nullglob #revert nullglob back to it's normal default state
.done >results.out
(et probablement alors vous pouvez écraser au lieu d'ajouter, comme je l'ai supposé ici).Que dis-tu de ça:
-maxdepth 1
L'argument empêche la recherche de descendre récursivement dans les sous-répertoires. (Si vous souhaitez que ces répertoires imbriqués soient traités, vous pouvez omettre cela.)-type -f
spécifie que seuls les fichiers ordinaires seront traités.-exec cmd option {}
lui dit de s'exécutercmd
avec le spécifiéoption
pour chaque fichier trouvé, avec le nom de fichier substitué pour{}
\;
indique la fin de la commande.cmd
exécutions individuelles est redirigée versresults.out
Cependant, si vous vous souciez de l'ordre dans lequel les fichiers sont traités, vous feriez mieux d'écrire une boucle. Je pense que
find
traite les fichiers dans l'ordre des inodes (bien que je puisse me tromper à ce sujet), ce qui n'est peut-être pas ce que vous voulez.la source
stat
etsort
, qui dépendent bien sûr des critères de tri.-exec
option? Dois-je les mettre entre guillemets simples ou quelque chose?find
est toujours la meilleure option car vous pouvez filtrer par modèle de nom de fichier avec option-name
et vous pouvez le faire en une seule commande.-exec
options:find . -name "*.txt" -exec echo {} \; -exec grep banana {} \;
Je fais cela sur mon Raspberry Pi à partir de la ligne de commande en exécutant:
la source
Les réponses acceptées / à vote élevé sont excellentes, mais elles manquent de quelques détails concrets. Cette publication couvre les cas sur la façon de mieux gérer lorsque l'expansion du nom de chemin du shell (glob) échoue, lorsque les noms de fichiers contiennent des sauts de ligne / symboles de tiret et le déplacement de la direction de sortie de la commande hors de la boucle for lors de l'écriture des résultats dans un fichier.
Lors de l'exécution de l'expansion du shell shell à l'aide de l'extension,
*
il est possible que l'expansion échoue s'il n'y a aucun fichier dans le répertoire et une chaîne glob non développée sera transmise à la commande à exécuter, ce qui pourrait avoir des résultats indésirables. Lebash
shell fournit une option shell étendue pour cette utilisationnullglob
. Ainsi, la boucle devient essentiellement la suivante dans le répertoire contenant vos fichiersCela vous permet de quitter en toute sécurité la boucle for lorsque l'expression
./*
ne renvoie aucun fichier (si le répertoire est vide)ou d'une manière conforme POSIX (
nullglob
estbash
spécifique)Cela vous permet d'aller à l'intérieur de la boucle lorsque l'expression échoue pour une fois et la condition
[ -f "$file" ]
vérifie si la chaîne non développée./*
est un nom de fichier valide dans ce répertoire, ce qui ne le serait pas. Donc, en cas d'échec de cette condition, en utilisantcontinue
nous reprenons lafor
boucle qui ne s'exécutera pas par la suite.Notez également l'utilisation de
--
juste avant de passer l'argument du nom de fichier. Cela est nécessaire car, comme indiqué précédemment, les noms de fichiers du shell peuvent contenir des tirets n'importe où dans le nom de fichier. Certaines des commandes shell l'interprètent et les traitent comme une option de commande lorsque le nom n'est pas cité correctement et exécute la commande en pensant si l'indicateur est fourni.Le
--
signale la fin des options de ligne de commande dans ce cas, ce qui signifie que la commande ne doit pas analyser les chaînes au-delà de ce point en tant que drapeaux de commande, mais uniquement en tant que noms de fichiers.La citation double des noms de fichiers résout correctement les cas où les noms contiennent des caractères globaux ou des espaces blancs. Mais les noms de fichiers * nix peuvent également contenir des retours à la ligne. Nous limitons donc les noms de fichiers avec le seul caractère qui ne peut pas faire partie d'un nom de fichier valide - l'octet nul (
\0
). Comme ilbash
utilise en interne desC
chaînes de style dans lesquelles les octets nuls sont utilisés pour indiquer la fin de la chaîne, c'est le bon candidat pour cela.Donc, en utilisant l'
printf
option shell pour délimiter les fichiers avec cet octet NULL en utilisant l'-d
option deread
commande, nous pouvons faire ci-dessousLe
nullglob
et leprintf
sont entourés,(..)
ce qui signifie qu'ils sont essentiellement exécutés dans un sous-shell (shell enfant), car pour éviter l'nullglob
option de réfléchir sur le shell parent, une fois la commande terminée. L'-d ''
option deread
commande n'est pas compatible POSIX, a donc besoin d'unbash
shell pour cela. En utilisant lafind
commande, cela peut être fait commePour les
find
implémentations qui ne prennent pas en charge-print0
(autres que les implémentations GNU et FreeBSD), cela peut être émulé en utilisantprintf
Un autre correctif important consiste à déplacer la redirection hors de la boucle for pour réduire un nombre élevé d'E / S de fichiers. Lorsqu'il est utilisé à l'intérieur de la boucle, le shell doit exécuter des appels système deux fois pour chaque itération de la boucle for, une fois pour ouvrir et une fois pour fermer le descripteur de fichier associé au fichier. Cela deviendra un goulot d'étranglement sur vos performances pour l'exécution de grandes itérations. La suggestion recommandée serait de le déplacer hors de la boucle.
En étendant le code ci-dessus avec ces correctifs, vous pouvez le faire
qui placera essentiellement le contenu de votre commande pour chaque itération de votre entrée de fichier dans stdout et lorsque la boucle se terminera, ouvrez le fichier cible une fois pour écrire le contenu de la stdout et l'enregistrer. La
find
version équivalente de la même seraitla source
Un moyen rapide et sale qui fait parfois le travail est:
Par exemple, pour trouver le nombre de lignes dans tous les fichiers du répertoire courant, vous pouvez faire:
la source
~/.local/share/steam
. Ran Steam. Il a supprimé tout sur le système appartenant à l'utilisateur." rapport d'erreur.J'avais besoin de copier tous les fichiers .md d'un répertoire dans un autre, alors voici ce que j'ai fait.
for i in **/*.md;do mkdir -p ../docs/"$i" && rm -r ../docs/"$i" && cp "$i" "../docs/$i" && echo "$i -> ../docs/$i"; done
Ce qui est assez difficile à lire, alors décomposons-le.
premier cd dans le répertoire avec vos fichiers,
for i in **/*.md;
pour chaque fichier de votre modèlemkdir -p ../docs/"$i"
créez ce répertoire dans un dossier docs en dehors du dossier contenant vos fichiers. Ce qui crée un dossier supplémentaire avec le même nom que ce fichier.rm -r ../docs/"$i"
supprimer le dossier supplémentaire créé à la suite demkdir -p
cp "$i" "../docs/$i"
Copiez le fichier réelecho "$i -> ../docs/$i"
Faites écho à ce que vous avez fait; done
Vivre heureux pour toujoursla source
**
fonctionner, l'globstar
option shell doit être définie:shopt -s globstar
Vous pouvez utiliser
xarg
ls | xargs -L 1 -d '\n' your-desired-command
-L 1
fait passer 1 élément à la fois-d '\n'
make output ofls
est divisé en fonction de la nouvelle ligne.la source
Basé sur l'approche de @Jim Lewis:
Voici une solution rapide utilisant
find
et triant également les fichiers par date de modification:Pour le tri, voir:
http://www.commandlinefu.com/commands/view/5720/find-files-and-list-them-sorted-by-modification-time
la source
-print0
pourfind
et-0
pourxargs
qui utilisent le caractère nul au lieu de les espaces blancs (y compris les nouvelles lignes).-print0
est quelque chose qui aide, mais l'ensemble du pipeline doit utiliser quelque chose comme ça, et cesort
n'est pas le casje pense que la solution simple est:
la source
Profondeur max
J'ai trouvé que cela fonctionne bien avec la réponse de Jim Lewis, ajoutez simplement un peu comme ceci:
Ordre de tri
Si vous souhaitez exécuter dans l'ordre de tri, modifiez-le comme ceci:
Juste pour un exemple, cela s'exécutera dans l'ordre suivant:
Profondeur illimitée
Si vous souhaitez exécuter en profondeur illimitée par certaines conditions, vous pouvez utiliser ceci:
puis placez au-dessus de chaque fichier dans les répertoires enfants comme ceci:
et quelque part dans le corps du fichier parent:
la source