Rinomina più file con mv per modificare l'estensione


27

Voglio rinominare i file per cambiare la loro estensione, cercando effettivamente di realizzare

mv *.txt *.tsv

Ma facendo questo ottengo:

* .tsv non è una directory

Trovo un po 'strano che i primi 10 hit di google show mvfunzionino in questo modo.


Dovresti spiegare come vuoi rinominare esattamente quei file.
Totor,

1
Bene ho dei file con un'estensione di * .gappedPeak e voglio rinominarli in * .bed. sono tutti nella stessa directory, dovrebbe essere molto semplice, ma per avere successo era necessario un loop completo
Sander Van der Zeeuw,

Quello che hai trovato su Google si applica a MSDOS penso.
tiktak,

La soluzione alternativa di @devnull è davvero utile
lucasvw,

Risposte:


22

Quando si emette il comando:

mv *.txt *.tsv

la shell, supponiamo bash, espande i caratteri jolly se ci sono file corrispondenti (comprese le directory). L'elenco dei file viene passato al programma, qui mv. Se non viene trovata alcuna corrispondenza, viene passata la versione non espansa.

Ancora: la shell espande gli schemi, non il programma.


Un sacco di esempi è forse il modo migliore, quindi eccoci qui:

Esempio 1:

$ ls
file1.txt file2.txt

$ mv *.txt *.tsv

Ora ciò che accade sulla mvlinea è che la shell si espande *.txtnei file corrispondenti. Poiché non ci sono *.tsvfile che non sono stati modificati.

Il mvcomando viene chiamato con due argomenti speciali :

  • argc: Numero di argomenti, incluso il programma.
  • argv: Una serie di argomenti, incluso il programma come prima voce.

Nell'esempio sopra che sarebbe:

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

Il mvprogramma controlla se l'ultimo argomento *.tsvè una directory. Altrimenti, il programma non può continuare in quanto non è progettato per concatenare i file. (In genere sposta tutti i file in uno.) Né crea directory per un capriccio.

Di conseguenza si interrompe e segnala l'errore:

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

Esempio 2:

Ora se invece dici:

$ mv *1.txt *.tsv

Il mvcomando viene eseguito con:

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

Ora, di nuovo, mvcontrolla per vedere se *.tsvesiste. In caso contrario, il file file1.txtviene spostato in *.tsv. Cioè: il file viene rinominato *.tsvcon l'asterisco e tutti.

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

$ ls
file2.txt *.tsv

Esempio 3:

Se invece hai detto:

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

Il mvcomando viene eseguito con:

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

Poiché *.tsvora è una directory, i file finiscono per essere spostati lì.


Ora: usando comandi come some_command *.tsvquando l'intenzione è quella di mantenere il carattere jolly si dovrebbe sempre citarlo. Citando, impedisci l'espansione dei caratteri jolly in caso di corrispondenze. Ad esempio dire mkdir "*.tsv".

Esempio 4:

L'espansione può essere ulteriormente visualizzata se lo fai ad esempio:

$ ls
file1.txt file2.txt

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

Esempio 5:

Ora: il mvcomando può e funziona su più file. Ma se ce ne sono più di due, l'ultimo deve essere una directory di destinazione. (Opzionalmente puoi usare l' -t TARGET_DIRopzione, almeno per GNU mv.)

Quindi va bene:

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

$ mv *.txt *.tsv foo

Qui mvsarebbe chiamato con:

 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

e tutti i file finiscono nella directory foo.


Per quanto riguarda i tuoi link. Ne hai fornito uno (in un commento), dove mvnon è menzionato affatto, ma rename. Se hai più link che potresti condividere. Così come per le pagine man in cui si afferma che questo è espresso.


30

So che questo non risponde alla tua domanda, ma nel caso stavi cercando un altro modo per rinominare i file rispetto al tuo ciclo di lavoro, perché non utilizzarlo find? Ho usato questo comando molte volte per sostituire le estensioni di file in grandi directory con centinaia di migliaia di file. Questo dovrebbe funzionare su qualsiasi sistema conforme a POSIX:

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

Ripartizione dei comandi:

  1. ' .' => percorso di ricerca che inizia nella directory corrente contrassegnata da '. '

  2. -name=> imposta trova nome corrispondenza (in questo caso tutti i file che terminano con .gappedPeak)

  3. -exec => esegui il seguente comando su ogni corrispondenza

  4. sh -c => 'exec' crea un ambiente shell indipendente per ogni corrispondenza

  5. mv "$1" "${1%.gappedPeak}.bed"=> mvprima variabile (indicata da $ 1 ), che è il nome del file corrente, con il nuovo nome. Qui faccio una corrispondenza di sottostringa ed elimina; quindi prendi di nuovo il primo var, $ 1 e usa %per cancellare .gappedPeakdalla stringa. .bedL'all'estremità appena concatena la variabile rimanente, che è ora solo , con , creando il nuovo nome file.test#.bedtest#.bed

  6. Il carattere di sottolineatura è un segnaposto per $ 0

  7. Il {}è sostituito da ciascuna ( *.gappedPeak) il nome del file trovato dal findcomando e diventa $ 1 al shcomando.

  8. \;segna la fine del -execcomando. Puoi anche usare ';'o ";".

Esempio:

[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

Potresti passare attraverso il comando che descrive cosa fa ogni parte?
user1717828,

Mi dispiace, ho aggiornato il mio post. Spero che sia d'aiuto.
Devnull,

1
Fantastico, grazie! Con una guida bash e la tua spiegazione sono stato in grado di ottenere tutto.
user1717828,

Nessun problema. Sono contento che aiuti.
Devnull,

Funziona come un fascino. Ecco un altro esempio semplificato di file.abc-> blub.xyzin più sottodirectory:find . -name "file.abc" -exec sh -c 'mv "$1" "$(dirname $1)/blub.xyz"' _ {} \;
Mahn

9

mv *.txt *.tsvnon funziona; mvpuò rinominare solo un file alla volta. O hai frainteso le spiegazioni o sono sbagliate.

mmve renamepuò rinominare più file contemporaneamente. Ma ci sono due versioni di renamearound che sono chiamate in modo diverso. Ci dovrebbero essere molte domande al riguardo qui.


1
cyberciti.biz/tips/… Il primo hit su google sta dicendo che anche mv dovrebbe funzionare, ecco perché l'ho trovato così strano
Sander Van der Zeeuw,

3
@SanderVanderZeeuw Non so cosa hai letto lì. Gli esempi usano rename, no mv.
Hauke ​​Laging,

1
scusa se ho incollato l'HTML sbagliato. Questo era quello udemy.com/blog/rename-a-file-in-linux
Sander Van der Zeeuw,

3
@SanderVanderZeeuw Imbarazzante. Queste persone offrono corsi? Purtroppo non vedo alcuna possibilità di contatto lì. Puoi facilmente verificare se funziona. Ma in mv *.txt *.tsv mv(di solito) non vede *.txto *.tsvma i nomi dei file espansi dalla shell. Il numero di file a cui questi caratteri jolly si espandono sarebbe "casuale". L'unica situazione in cui funziona è se esiste un file con il nome *.txtche deve essere rinominato (letteralmente) *.tsv(senza virgolette, l' bashopzione nullglobnon deve essere impostata).
Hauke ​​Laging,

1
O peggio. Se uno ha un file chiamato ad esempio foo.txte uno chiamato baz.tsvil mv *.txt *.tsvsovrascriverà quella esistente .tsvfile di ...
Runium

4

Ad esempio, se si hanno asd.txte qwe.txtfile nella directory quando si esegue il comando mv *.txt *.tsv, prova a spostare questi due file in una directory denominata *.tsv. Poiché non esiste tale directory, viene visualizzato un errore.


Grazie, questo chiarisce parzialmente. Tuttavia trovo strano che io veda così tante pagine di manuale in cui sostengono che mv dovrebbe funzionare su più.
Sander Van der Zeeuw,

2

rename(1)

renameè uno script perl di Larry Wall il creatore di perl. Prende una regex Perl e opera sul nome del file.

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

Installazione

Debian / Ubuntu

Se devi installarlo renamesu Debian / Ubuntu puoi farlo

sudo apt install rename

0

Un'altra opzione da considerare è l'utilizzo di:

cp -p *.txt *.tsv
rm -f *.txt
  • La prima riga copia tutti i *.txtfile *.tsvpreservando i loro attributi usando il -pflag.
  • La seconda riga rimuove tutti i file con il modello *.txt
  • Questo metodo richiede spazio su disco sufficiente per contenere temporaneamente sia i file di origine che quelli di destinazione
  • Questo metodo è più lento di quello mvche modifica semplicemente la directory / nomefile senza spostare effettivamente i file a meno che non si trovino in una partizione diversa.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.