web-dev-qa-db-fra.com

Renommez plusieurs fichiers avec mv pour changer l'extension

Je veux renommer des fichiers pour changer leur extension, en cherchant efficacement à accomplir

mv *.txt *.tsv

Mais en faisant cela, je reçois:

* .tsv n'est pas un répertoire

Je trouve quelque peu étrange que les 10 premiers hits google montrent que mv devrait fonctionner comme ceci.

30

Lorsque vous exécutez la commande:

mv *.txt *.tsv

le Shell, supposons bash, développe les caractères génériques si il existe des fichiers correspondants (y compris les répertoires). La liste des fichiers est passée au programme, ici mv. Si aucune correspondance n'est trouvée, la version non étendue est transmise.

Encore une fois: le Shell développe les modèles, pas le programme.


Beaucoup d'exemples est peut-être le meilleur moyen, alors c'est parti:

Exemple 1:

$ ls
file1.txt file2.txt

$ mv *.txt *.tsv

Maintenant, ce qui se passe sur la ligne mv est que le Shell se développe *.txt aux fichiers correspondants. Comme il n'y a pas de *.tsv fichiers non modifiés.

La commande mv est appelée avec deux arguments spéciaux :

  • argc: nombre d'arguments, y compris le programme.
  • argv: un tableau d'arguments, y compris le programme comme première entrée.

Dans l'exemple ci-dessus, ce serait:

 argc = 4
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = file2.txt
 argv[3] = *.tsv

Le programme mv vérifie si le dernier argument, *.tsv, est un directeur. Comme il ne l'est pas, le programme ne peut pas continuer car il n'est pas conçu pour concaténer des fichiers. (Déplacez généralement tous les fichiers en un seul.) Ni créez de répertoires sur un coup de tête.

En conséquence, il abandonne et signale l'erreur:

mv: target ‘*.tsv’ is not a directory

Exemple 2:

Maintenant, si vous dites à la place:

$ mv *1.txt *.tsv

La commande mv est exécutée avec:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = *.tsv

Maintenant, encore une fois, mv vérifie si *.tsv existe. Comme il ne fait pas le fichier file1.txt est déplacé vers *.tsv. C'est-à-dire: le fichier est renommé en *.tsv avec l'astérisque et tout.

$ mv *1.txt *.tsv
‘file1.txt’ -> ‘*.tsv’

$ ls
file2.txt *.tsv

Exemple 3:

Si vous avez plutôt dit:

$ mkdir *.tsv
$ mv *.txt *.tsv

La commande mv est exécutée avec:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[1] = file2.txt
 argv[2] = *.tsv

Comme *.tsv est maintenant un répertoire, les fichiers finissent par y être déplacés.


Maintenant: en utilisant des commandes comme some_command *.tsv lorsque l'intention est de conserver le caractère générique, il faut toujours le citer. En citant, vous empêchez les caractères génériques d'être étendus s'il doit y avoir des correspondances. Par exemple. dire mkdir "*.tsv".

Exemple 4:

L'extension peut encore être visualisée si vous faites par exemple:

$ ls
file1.txt file2.txt

$ mkdir *.txt
mkdir: cannot create directory ‘file1.txt’: File exists
mkdir: cannot create directory ‘file2.txt’: File exists

Exemple 5:

Maintenant: la commande mv peut et fonctionne sur plusieurs fichiers. Mais s'il y en a plus de deux, le dernier doit être un répertoire cible. (Vous pouvez éventuellement utiliser le -t TARGET_DIR option, au moins pour GNU mv.)

Donc ça va:

$ ls -F
b1.tsv  b2.tsv  f1.txt  f2.txt  f3.txt  foo/

$ mv *.txt *.tsv foo

Ici, mv serait appelé avec:

 argc = 7
 argv[0] = mv
 argv[1] = b1.tsv
 argv[2] = b2.tsv
 argv[3] = f1.txt
 argv[4] = f2.txt
 argv[5] = f3.txt
 argv[6] = foo

et tous les fichiers se retrouvent dans le répertoire foo.


Quant à vos liens. Vous en avez fourni un (dans un commentaire), où mv n'est pas du tout mentionné, mais rename. Si vous avez plus de liens que vous pourriez partager. Ainsi que pour les pages de manuel où vous affirmez que cela est exprimé.

25
Runium

Je sais que cela ne répond pas à votre question, mais au cas où vous cherchiez une autre façon de renommer les fichiers par rapport à votre boucle de contournement, pourquoi ne pas utiliser find? J'ai utilisé cette commande plusieurs fois pour remplacer les extensions de fichier dans les grands répertoires par des centaines de milliers de fichiers. Cela devrait fonctionner sur tout système compatible POSIX:

find . -name "*.gappedPeak" -exec sh -c 'mv "$1" "${1%.gappedPeak}.bed"' _ {} \;

Répartition des commandes:

  1. ". '=> chemin de recherche commençant par le répertoire courant marqué par'. "

  2. -name => définir le nom de la correspondance de recherche (dans ce cas, tous les fichiers se terminant par .gappedPeak)

  3. -exec => exécuter la commande suivante à chaque correspondance

  4. sh -c => 'exec' crée un environnement Shell indépendant pour chaque correspondance

  5. mv "$1" "${1%.gappedPeak}.bed" => mv première variable (indiquée par $ 1), qui est le nom du fichier actuel, vers un nouveau nom. Ici, je fais une correspondance de sous-chaîne et je la supprime; alors prenez à nouveau la première var, $ 1 et utilisez % supprimer .gappedPeak à partir de la chaîne. Le .bed à la fin concatène simplement la variable restante, qui est maintenant juste test#, avec .bed, création du nouveau test#.bed nom de fichier.

  6. Le trait de soulignement est un espace réservé pour $

  7. Le {} est remplacé par chacun (*.gappedPeak) nom de fichier trouvé par la commande find et devient $ 1 à la commande sh.

  8. \; marque la fin du -exec commande. Vous pouvez aussi utiliser ';' ou ";".

Exemple:

[user@before]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.gappedPeak

[user@after]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.bed
33
devnull

mv *.txt *.tsv ne fonctionne pas; mv ne peut renommer qu'un seul fichier à la fois. Vous avez soit mal compris les explications, soit elles sont fausses.

mmv et rename peuvent renommer plusieurs fichiers à la fois. Mais il existe deux versions de rename autour desquelles sont appelées différemment. Il devrait y avoir beaucoup de questions à ce sujet ici.

9
Hauke Laging

Par exemple, si vous avez asd.txt et qwe.txt fichiers dans le répertoire lorsque vous exécutez la commande mv *.txt *.tsv, il essaie de déplacer ces deux fichiers dans un répertoire nommé *.tsv. Parce qu'il n'y a pas un tel répertoire, il donne une erreur.

4
Esref

rename(1)

rename est un script Perl de Larry Wall, le créateur de Perl. Il prend une expression rationnelle Perl et fonctionne sur le nom de fichier.

rename 's/\.txt$/.tsv/' *.txt

Installation

Debian/Ubuntu

Si vous devez installer rename sur Debian/Ubuntu, vous pouvez le faire

Sudo apt install rename
2
Evan Carroll

Une autre option à considérer consiste à utiliser:

cp -p *.txt *.tsv
rm -f *.txt
  • La première ligne copie tous les *.txt fichiers vers *.tsv tout en préservant leurs attributs à l'aide de -p drapeau.
  • La deuxième ligne supprime tous les fichiers avec le modèle *.txt
  • Cette méthode nécessite que vous disposiez de suffisamment d'espace disque pour contenir temporairement les fichiers source et cible
  • Cette méthode est plus lente que mv qui change simplement le répertoire/nom de fichier sans déplacer réellement les fichiers à moins qu'ils ne se trouvent sur une partition différente.
0
WinEunuuchs2Unix

Apparemment, le moyen le plus simple sous Linux OS est:

manual rename

  1. Cliquez sur le fichier
  2. Appuyez sur F2 (renommer)
  3. modifiez le nom du fichier comme vous le souhaitez
  4. appuyez sur <ENTER>

Je suppose que parfois DOS gagne. :)

0
raddevus