Fichier mv Linux avec nom long

19

Sous Linux, je renomme parfois des fichiers comme celui-ci:

mv dir1/dir2/dir3/file.txt  dir1/dir2/dir3/file.txt.old

Notez que je veux simplement renommer le fichier, pas le déplacer vers un autre répertoire.

Existe-t-il une commande qui me permettrait de faire une version abrégée de cette commande? Je pense à quelque chose comme:

mv dir1/dir2/dir3/file.txt  file.txt.old

ou peut-être même quelque chose comme (pour simplement ajouter au nom):

mv dir1/dir2/dir3/file.txt  {}.old

Mon objectif n'est pas de devoir spécifier à nouveau le chemin complet.

Je sais que les "exemples" que j'ai écrits ne fonctionnent pas, mais ce n'est qu'une idée de ce que je veux accomplir.

Je ne veux pas avoir à entrer dans le répertoire.

Santiago arizti
la source
8
Pourquoi ne passez-vous pas au répertoire? Il est rapide et résout votre problème.
Michael Hampton
Je traite de nombreux sous-répertoires de ce même emplacement, c'est plus lent si je dois revenir à chaque fois dans ce répertoire parent
santiago arizti
3
Personne n'a dit que vous deviez changer pour un autre répertoire, seulement celui que vous voulez.
Michael Hampton
Notez qu'il (cd dir1/dir2/dir3 && exec mv file.txt{,.old})a effectivement les mêmes performances que le code sans le sous-processus, car cela execévite l' fork()ing lors de l'appel de commande externe, vous avez donc exactement une fourchette dans les deux sens.
Charles Duffy

Réponses:

45

pour un seul fichier, essayez

mv dir1/dir2/dir3/file.{txt,txt.old}

où la X{a,b}construction s'étend Xa Xb, vous pouvez avoir un aperçu en utilisant

echo dir1/dir2/dir3/file.{txt,txt.old}

pour voir si cela correspond à vos besoins.

Remarque:

  1. que pour plusieurs fichiers

    mv dir1/dir2/dir3/file{1,2,3}.{txt,txt.old}
    

est peu susceptible de s'étendre à ce que vous voulez. (cela s'étendra à un mélange de fichier.txt fichier1.txt.old fichier2.txt ...)

  1. {txt,txt.old}peut être raccourci {,.old}selon le commentaire

  2. si le nom du répertoire n'est pas ambigu, le caractère générique peut être utilisé.

    mv *1/*2/d*/*.{,old}
    

pour plusieurs fichiers rename

rename -n s/txt/old.txt/ dir1/dir2/dir3/file*.txt 

drop -npour avoir un renommage efficace.

Archemar
la source
1
sympa, je ne connaissais pas cette façon de se développer! merci
santiago arizti
14
Ne fonctionnerait mv dir1/dir2/dir3/file.txt{,.old}pas aussi et serait encore plus court?
Josh
3
@Josh Oui, cela fonctionne parfaitement et nécessite moins de frappes. J'utilise cette construction très régulièrement.
rlf
2
c'est drôle comment vous pouvez utiliser le shell Linux pendant des années et toujours trouver de nouvelles astuces
santiago arizti
Je suppose que tous ces "trucs" seraient plus évidents si j'avais eu une formation formelle dans la langue bash, mais j'apprends juste assez pour m'entendre.
santiago arizti
6

La commande renamerenomme tous les fichiers correspondants. Son objectif principal est de renommer plusieurs fichiers, mais si l'expression Perl ne correspond qu'à un seul fichier, elle ne renommera alors que ce seul fichier. Pour plus de détails et de la syntaxe spécifique distro s'il vous plaît lire la page de manuel: man rename.

Exemple d'utilisation: renommez "/path/file.txt" en "/path/file.txt.old":

rename 's/file.txt/file.txt.old/g' /path/file.txt

Notation plus courte (grâce à shalomb):

rename 's/$/.old/' /path/file.txt
rename '$_.=".old"' /path/file.txt

Pour une utilisation à sec rename -n.

Plus d'exemples et de détails peuvent être trouvés sur https://thepcspy.com/read/bulk-rename-files-in-ubuntu/

Fabien
la source
cool, je connaissais la commande renommer, je ne savais tout simplement pas tout ce qu'elle pouvait faire, merci!
santiago arizti
6
Malheureusement, différentes distributions Linux ont des renamecommandes différentes avec un comportement complètement différent.
kasperd
1
Pour cette tâche particulière de changement de nom en ajoutant .oldau nom de fichier, il est probablement un peu plus pratique de faire un rename 's/$/.old/' /path/to/file.txtourename '$_.=".old"' /path/to/file.txt
shalomb
@Fabian - Je n'étais pas tatillonne, je visais juste la "main la plus courte" pour ce qui semble être un idiome fréquemment utilisé que l'OP recherche :)
shalomb
4

Pour un cas unique, si je ne veux pas changer mon répertoire actuel, je pourrais simplement utiliser un sous-shell:

(cd dir1/dir2/dir3/ && mv file.txt file.txt.old)

Parce que vous cdà l'intérieur du sous-shell, vous n'avez pas changé votre répertoire dans votre shell réel

Adam
la source
4
Plus rapide et plus sûr à utiliser && exec mv- de cette façon, vous n'essayez pas de renommer en cas d' cdéchec, et le execconsomme le sous-shell, évitant ainsi une pénalité de performance.
Charles Duffy
D'accord avec && Pour un cas unique, comme je l'ai dit, je ne m'inquiéterais pas du coût du sous-shell (restez simple: pouvoir se rappeler facilement comment le faire est plus important OMI)
Adam
Je dirais que si vous allez de se rappeler qu'une seule façon, se souvenant de la manière efficace permet de vous assurer que vous n'allez pas la route inefficace dans les cas où il fait affaire.
Charles Duffy
4

J'aime la solution de @ archemar d'utiliser l'expansion {}, car vous pouvez l'utiliser lorsque vous avez déjà démarré votre ligne de commande. Voici quelques autres possibilités d'exhaustivité:

F="dir1/dir2/dir3/file.txt" ; mv "$F" "$F.old"

(les guillemets ne sont nécessaires que si vous avez des espaces ou d'autres caractères de rupture de mot dans le nom)

mymv() {
    mv "$1/$2" "$1/$3"
}

mymv dir1/dir2/dir3 file.txt file.txt.old
mymv dir5/dir6/dir7 file.txt file.txt.old

Remarques:

  • Ceci est la syntaxe bash, vous utilisez peut-être un autre shell
  • mymv peut être n'importe quelle chaîne raisonnable, j'ai utilisé mymv pour "mon déménagement".
  • La définition de la fonction peut être placée dans votre .bash_profile

Un autre:

cd dir1/dir2/dir3 ; mv file.txt file.txt.old ; cd -

mais

(cd dir1/dir2/dir3/ && exec mv file.txt file.txt.old)

(de @Adam et @CharlesDuffy) est sans doute mieux en cas d'échec du cd.

Loi29
la source
1
Ne l'utilisez pas mmv, il existe déjà un programme nommé de cette façon.
glglgl
1
@glglgl Done :)
Law29
2

Si vous souhaitez entrer dans le sous-répertoire afin de raccourcir la mvcommande, mais souhaitez revenir au répertoire en cours par la suite, il existe deux façons de procéder. L'une consiste à mettre le cdet mvdans une sous-coque (comme cela a déjà été suggéré).

L'autre consiste à utiliser pushdet popdà changer de répertoire:

pushd dir1/dir2/dir3/; mv file.txt file.txt.old; popd

La pushdcommande est similaire cd, sauf qu'elle pousse d'abord le nom du répertoire courant sur une pile. popdsupprime le premier nom de la pile et modifie ce répertoire.

AndyB
la source
pushdet popdsont des extensions destinées à une utilisation interactive - POSIX les répertorie explicitement comme "les résultats ne sont pas spécifiés", et un shell conçu pour exécuter des scripts (c'est-à-dire sur un environnement embarqué minimal) n'a pas besoin de les prendre en charge.
Charles Duffy
2

Je ferais juste

cd dir1/dir2/dir3/
mv file.txt file.txt.old
cd ~- # go to the most recent directory
glglgl
la source
0

La solution impliquant: mv something{.txt,.txt.old}utilise un "bashisme". Si vous voulez un moyen plus portable, en utilisant des manipulations de variables courantes:

# rename all files "file*.txt" of directory /dir1/dir2/dir3 into file*.txt.old:
for f in dir1/dir2/dir3/file*.txt ; do
  mv "$f" "${f/.txt/.txt.old}"  # note there are no terminating "/"
done


# "${var/A/B}" is the content of var with the first occurence of "A" replaced by "B"
Olivier Dulac
la source
2
Voir pubs.opengroup.org/onlinepubs/009695399/utilities/… pour la spécification POSIX pertinente - ${var/text/replacement}est un bashisme lui-même.
Charles Duffy
@CharlesDuffy oh ... Tu me rends triste :(
Olivier Dulac