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.
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:
$ 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
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
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"
.
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
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é.
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:
"
.
'=> chemin de recherche commençant par le répertoire courant marqué par'. "
-name
=> définir le nom de la correspondance de recherche (dans ce cas, tous les fichiers se terminant par.gappedPeak
)
-exec
=> exécuter la commande suivante à chaque correspondance
sh -c
=> 'exec' crée un environnement Shell indépendant pour chaque correspondance
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 justetest#
, avec.bed
, création du nouveautest#.bed
nom de fichier.Le trait de soulignement est un espace réservé pour $
Le
{}
est remplacé par chacun (*.gappedPeak
) nom de fichier trouvé par la commandefind
et devient $ 1 à la commandesh
.
\;
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
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.
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.
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
Si vous devez installer rename
sur Debian/Ubuntu, vous pouvez le faire
Sudo apt install rename
Une autre option à considérer consiste à utiliser:
cp -p *.txt *.tsv
rm -f *.txt
*.txt
fichiers vers *.tsv
tout en préservant leurs attributs à l'aide de -p
drapeau.*.txt
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.