Supposons que je souhaite copier le contenu d'un répertoire à l'exclusion des fichiers et dossiers dont les noms contiennent le mot «Musique».
cp [exclude-matches] *Music* /target_directory
Qu'est-ce qui devrait remplacer [exclude-matches] pour accomplir cela?
bash
shell
pattern-matching
glob
utilisateur4812
la source
la source
ls /dir/*/!(base*)
f
, sauffoo
?L'
extglob
option shell vous donne une correspondance de motifs plus puissante dans la ligne de commande.Vous l'allumez avec
shopt -s extglob
et l'éteignez avecshopt -u extglob
.Dans votre exemple, vous feriez initialement:
Le complet est disponible poste a pris fin glob opérateurs bing sont (extrait
man bash
):Ainsi, par exemple, si vous vouliez lister tous les fichiers du répertoire courant qui ne le sont pas
.c
ou les.h
fichiers, vous feriez:Bien sûr, le globing shell normal fonctionne, donc le dernier exemple pourrait également s'écrire:
la source
.c
ou.h
est un répertoire.D
, mais pas le contenu des sous-répertoires qui peuvent être contenus dans le répertoireD
.Pas en bash (que je sache), mais:
Je sais que ce n'est pas exactement ce que vous cherchiez, mais cela résoudra votre exemple.
la source
Si vous voulez éviter le coût mem de l'utilisation de la commande exec, je pense que vous pouvez faire mieux avec xargs. Je pense que ce qui suit est une alternative plus efficace à
la source
En bash, une alternative à
shopt -s extglob
est laGLOBIGNORE
variable . Ce n'est pas vraiment mieux, mais je trouve ça plus facile à retenir.Un exemple qui pourrait être ce que l'affiche originale voulait:
Une fois terminé,
unset GLOBIGNORE
pour pouvoirrm *techno*
dans le répertoire source.la source
Vous pouvez également utiliser une
for
boucle assez simple :la source
-maxdepth 1
pour non récursif?find
de backticks se brisera de manière désagréable si elle trouve des noms de fichiers non triviaux.Ma préférence personnelle est d'utiliser grep et la commande while. Cela permet d'écrire des scripts puissants mais lisibles en vous assurant de faire exactement ce que vous voulez. De plus, en utilisant une commande d'écho, vous pouvez effectuer un essai à sec avant d'effectuer l'opération réelle. Par exemple:
imprimera les fichiers que vous finirez par copier. Si la liste est correcte, l'étape suivante consiste à remplacer simplement la commande echo par la commande copy comme suit:
la source
bash
vous pouvez utiliserwhile IFS='' read -r filename
, mais les sauts de ligne restent un problème. En général, il est préférable de ne pas utiliserls
pour énumérer les fichiers; des outils commefind
sont beaucoup mieux adaptés.for file in *; do case ${file} in (*Music*) ;; (*) cp "${file}" /target_directory ; echo ;; esac; done
Un truc que je ne l' ai pas vu ici encore qui n'utilise pas
extglob
,find
ougrep
est de traiter deux listes de fichiers comme des ensembles et « diff » en les utilisantcomm
:comm
est préférablediff
car il ne contient pas de cruches supplémentairesCela renvoie tous les éléments de l'ensemble 1,,
ls
qui ne sont pas également dans l'ensemble 2ls *Music*
,. Cela nécessite que les deux ensembles soient triés pour fonctionner correctement. Pas de problème pourls
et l'expansion globale, mais si vous utilisez quelque chose commefind
, assurez-vous d'invoquersort
.Potentiellement utile.
la source
comm -23 <(ls) exclude_these.list
Une solution pour cela peut être trouvée avec find.
Find a plusieurs options, vous pouvez être assez précis sur ce que vous incluez et excluez.
Edit: Adam dans les commentaires a noté que c'est récursif. les options mindepth et maxdepth peuvent être utiles pour contrôler cela.
la source
find -maxdepth 1 -not -name '*Music*'
/ target_directoryLes travaux suivants répertorient tous les
*.txt
fichiers du répertoire en cours, à l'exception de ceux qui commencent par un nombre.Cela fonctionne
bash
,dash
,zsh
et tous les autres shells compatibles POSIX.Dans la première ligne, le motif
/some/dir/*.txt
provoquera l'for
itération de la boucle sur tous les fichiers/some/dir
dont le nom se termine par.txt
.Dans la ligne deux, une déclaration de cas est utilisée pour éliminer les fichiers indésirables. - L'
${FILE##*/}
expression retire tout composant de nom de/some/dir/
répertoire principal du nom de fichier (ici ) afin que les patters puissent correspondre uniquement avec le nom de base du fichier. (Si vous ne supprimez que les noms de fichiers basés sur des suffixes, vous pouvez les raccourcir à la$FILE
place.)À la ligne 3, tous les fichiers correspondant au
case
modèle[0-9]*
) seront ignorés (l'continue
instruction passe à l'itération suivante de lafor
boucle). - Si vous le souhaitez, vous pouvez faire quelque chose de plus intéressant ici, par exemple, ignorer tous les fichiers qui ne commencent pas par une lettre (a – z)[!a-z]*
, ou vous pouvez utiliser plusieurs modèles pour ignorer plusieurs types de noms de fichiers, par exemple[0-9]*|*.bak
pour ignorer les fichiers des deux.bak
fichiers et les fichiers qui ne commencent pas par un nombre.la source
*.txt
au lieu de juste*
). Fixé maintenant.cela le ferait en excluant exactement «Musique»
ceci et cela pour exclure des choses comme la musique? * ou *? la musique
la source
cp
page de manuel sur MacOS a une-a
option mais elle fait quelque chose de complètement différent. Quelle plateforme prend en charge cela?