Comment copier des fichiers en shell qui ne se terminent pas par une certaine extension de fichier

Par exemple, copiez tous les fichiers qui ne se terminent pas par .txt

Bash acceptera un modèle non.

cp !(*.txt) 

Vous pouvez utiliser ls avec l’option grep -v:

 for i in `ls | grep -v ".txt"` do cp $i $dest_dir done 

Selon le nombre d’hypothèses que vous pouvez vous permettre concernant les caractères des noms de fichiers, cela peut être aussi simple que:

 cp $(ls | grep -v '\.txt$') /some/other/place 

Si cela ne fonctionne pas pour vous, alors peut-être find ... -print0 | xargs -0 cp ... find ... -print0 | xargs -0 cp ... peut être utilisé à la place (bien que cela ait des problèmes – car la destination se trouve à la fin de la liste des arguments).

Sur MacOS X, xargs a une option -J qui prend en charge ce qui est nécessaire:

-J replstr

Si cette option est spécifiée, xargs utilisera les données lues depuis l’entrée standard pour remplacer la première occurrence de replstr au lieu d’append ces données après tous les autres arguments. Cette option n’affectera pas le nombre d’arguments à lire depuis l’entrée (-n), ou la taille des commandes xargs générera (-s). L’option se déplace simplement là où ces arguments seront placés dans la ou les commandes exécutées. Le replstr doit apparaître comme un argument distinct de xargs. Il ne sera pas reconnu si, par exemple, il est au milieu d’une chaîne entre guillemets. De plus, seule la première occurrence de la replstr sera remplacée. Par exemple, la commande suivante va copier la liste des fichiers et répertoires commençant par une lettre majuscule dans le répertoire en cours vers destdir:

 /bin/ls -1d [AZ]* | xargs -J % cp -rp % destdir 

Il semblerait que GNU xargs ne possède pas -J mais possède l’option -I associée mais légèrement ressortingctive (qui est également présente dans MacOS X):

-I replace-str

Remplacez les occurrences de replace-str dans les arguments initiaux par les noms lus à partir de l’entrée standard. De plus, les blancs non cotés ne terminent pas les éléments en entrée; à la place, le séparateur est le caractère de nouvelle ligne. Implique -x et -L 1.

Vous pouvez compter sur:

 find . -not -name "*.txt" 

En utilisant:

 find -x . -not -name "*.txt" -d 1 -exec cp '{}' toto/ \;` 

Qui copie tous les fichiers qui ne sont pas .txt du répertoire en cours dans un sous-répertoire toto /. le -d 1 est utilisé pour empêcher la récursivité ici.

Soit faire:

 for f in $(ls | grep -v "\.txt$") do cp -- "$f" ⟨destination-directory⟩ done 

ou si vous avez une quantité énorme de fichiers:

 find -prune \! -name "*.txt" -exec cp -- "{}" ⟨destination-directory⟩ .. \; 

Deux choses ici pour commenter. L’une est l’utilisation du double trait d’union dans l’invocation de cp et la citation de $f . Les premiers gardes contre les noms de fichiers “farfelus” qui commencent par un tiret peuvent être interprétés comme des options. Le second protège les noms de fichiers avec des espaces (ou ce que IFS ).

Dans zsh :

 setopt extendedglob cp *^.txt /some/folder 

(si vous voulez juste des fichiers ) …

 cp *.^txt(.) /some/folder 

Plus d’informations sur zsh globbing ici et ici .

Je le ferais comme ça, où destination est le répertoire de destination:

 ls | grep -v "\.txt$" | xargs cp -t destination 

Edit: ajouté “-t” grâce aux commentaires