Come copio più file con caratteri jolly?


42

Ho una cartella con un numero di file in esso ABC. * (Ci sono circa 100 di questi file). Voglio duplicarli tutti in nuovi file con nomi che iniziano con DEF. *

Così io voglio

ABC.Page1
ABC.Page2
ABC.Topic12
...etc

copiato in

DEF.Page1
DEF.Page2
DEF.Topic12
...etc

Qual è il modo più semplice per farlo con un comando batch (in BASH o simile)? Sto pensando a qualcosa che coinvolge sed o awk o xargs, ma ho difficoltà a capire la sintassi. Potrei scrivere uno script Python, ma sto pensando che probabilmente esiste una soluzione a riga di comando che non è troppo complicata.


Un venerabile mcgestore di file ha un supporto molto esteso per questo tipo di rinominazioni di massa.
Oakad,

@oakad tarnon è neanche un pollo primaverile. Vedi la mia risposta per un esempio.
Mikeserv,

Risposte:


41

Che ne dici di qualcosa del genere in bash:

for file in ABC.*; do cp "$file" "${file/ABC/DEF}";done

puoi testarlo mettendo echo davanti al comando cp:

for file in ABC.*; do echo cp "$file" "${file/ABC/DEF}";done

perfezionare. ancora più semplice di quanto immaginassi.
Polpo

Nella maggior parte dei casi sarà abbastanza buono, ma controllare con l'eco è cruciale qui. Non farlo mai in una sceneggiatura . Per maggiori informazioni leggi le insidie ​​di bash
pawel7318,

@ pawel7318, il link che hai dato, sebbene un consiglio eccellente, non sembra applicarsi al comando dato sopra. Gli unici casi limite che vedo con questo comando sono: (1) Non controlla se il file di destinazione esiste già se il file di destinazione esiste già come directory (che copia il file nella directory, conservando il nome corrente), e (2) se ci sono così tanti file che l'espansione glob non può rientrare in una singola riga di comando.
Wildcard il

1
Ho capito: cp /usr/local/lib/libboost* /usr/local/lib/libboost*con il controllo dell'eco.
Tomáš Zato,

8

Per farlo in modo efficiente con un gran numero di file, è meglio evitare di avviare un cpprocesso diverso per ognuno. Un modo sarebbe quello di copiarli e rinominarli usando prename( renameper impostazione predefinita è collegato a questo su distribuzioni basate su Debian). Usando questo e Linux mktemp:

tmp=$(mktemp -d --tmpdir=.)
cp ABC.* "$tmp"
prename "s:$tmp/ABC:DEF:" "$tmp/"*
rmdir "$tmp"

Aggiornare

In realtà paxpotrebbe essere un modo migliore per andare qui:

pax -rws '/^ABC/DEF/' ABC.* .

Sfortunatamente, nonostante paxsia POSIX e Linux Standard Base, poche distribuzioni lo includono attualmente per impostazione predefinita.


bel tocco usando: come separatore per evitare la fuga.
Clayton Stanley,

5

tar lo farà per te molto velocemente.

TEST

Per prima cosa ho creato 2 directory e 10 file:

% mkdir test1 test2 ; cd test1
% for n in `seq 1 10` ; do touch ABC.file$n ; done
% ls

> ABC.file1   ABC.file2  ABC.file4  ABC.file6  ABC.file8
> ABC.file10  ABC.file3  ABC.file5  ABC.file7  ABC.file9

Poi le ho copiate:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC/DEF/' -xf -
% ls ../test2

> DEF.file1   DEF.file2  DEF.file4  DEF.file6  DEF.file8
> DEF.file10  DEF.file3  DEF.file5  DEF.file7  DEF.file9

TRASFORMARE

Quindi GNU taraccetterà un sed --transform=EXPRESSIONper rinominare i file. Questo può anche rinominare solo alcuni dei file. Per esempio:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC\(.*[0-5]\)/DEF\1/' -xf -
% ls ../test2

> ABC.file6  ABC.file8  DEF.file1   DEF.file2  DEF.file4
> ABC.file7  ABC.file9  DEF.file10  DEF.file3  DEF.file5

Quindi questo è un vantaggio.

STREAM

Considera anche che si tratta solo di due tarprocessi e che non cambierà indipendentemente dal conteggio dei file.

tar | tar

tarè ottimizzato come si potrebbe desiderare. Ciò non avrà mai conteggi di argomenti problematici o processi figlio in fuga. Questo è solo A> B. fatto.

ARGOMENTI

Uso 7 argomenti distinti combinati tra i miei due tarprocessi qui. Quello più importante è elencato qui prima:

-stdout / stdin - questo informa tarche eseguirà lo streaming del suo input o output verso o dal stdin/stdoutquale interpreterà correttamente a seconda che stia costruendo o estraendo o meno un archivio.

-ccrea - questo dice tardi costruire l'archivio. Il prossimo argomento tarprevede che ...

-ffile : specifichiamo che tarfunzionerà con un fileoggetto anziché con un dispositivo a nastro o altro. E il file con cui lavorerà, come notato sopra, è stdin/stdout- in altre parole, il nostro |pipe.

./*tutti i $ PWD / file - non c'è molto da spiegare qui, tranne per il fatto che l'argomento di archivio viene prima, -quindi ./*.

... e dall'altra parte del |pipe...

-Ccambia directory : informa tarche deve passare alla directory specificata prima di eseguire qualsiasi altra azione, in modo efficace appena cd ../test2prima dell'estrazione.

--transform='s/ed/EXPR/'- come già accennato, ciò ha comportato la ridenominazione. Ma i documenti indicano che può prendere qualsiasi sedespressione o //flag.

-xextract - dopo aver tarapportato modifiche alla nostra directory di destinazione e riceve le nostre istruzioni di ridenominazione, le chiediamo di iniziare a estrarre tutti i file nella sua directory corrente dal -f - |pipefile di archivio. Nessun mistero.


1
Ecco la paxsoluzione per questa domanda. Lo aggiungerei alla mia risposta, ma penso che sia più adatto qui -pax -rws '/^ABC/DEF/' ABC.* .
Graeme

@Graeme - woah - è molto meglio! Amico, batte anche l'inferno di un nuovo nome di perla! Dovresti inserirlo nella tua risposta - paxè specificato POSIX - da qui il pax.
Mikeserv,

paxpotrebbe essere POSIX, ma purtroppo raramente è installato di default.
Graeme,

4

Se non ti dispiace usare uno strumento meno standard, ti consiglio di usare mmv (spostamento di massa) che è stato scritto per questo tipo di attività. Usando mcp(copia di massa), che fa parte della suite, potresti semplicemente farlo

mcp "ABC.*" "DEF.#1"

Non è esattamente facile trovare i pacchetti di download. Il pacchetto Debian corrente (che Arch usa anche in AUR) per compilare a casa può essere trovato qui .


installa su Ubuntu 15.10 out of the box,apt-get install mmv
Giovedì

2

In zsh, inserisci le seguenti righe nel tuo .zshrc:

autoload -U zmv
alias zmv='noglob zmv'
alias zcp='zmv -C'
alias zln='zmv -L'

Quindi, dalla riga di comando, è possibile eseguire

zcp 'ABC(.*)' 'DEF$1'

o semplicemente

zcp -W ABC.* DEF.*

In un'altra shell, purché tu abbia installato zsh:

zsh -c 'autoload zmv; noglob zmv -CW ABC.* DEF.*'

1

Potresti farlo:

for i in ABC.*; do cp {ABC,DEF}."${i#*.}"; done

Forse c'è qualcosa che non vedo, ma come sto impostando più destinazioni? Sto usando il ciclo for per ottenere ciascuno. Ho testato il codice in anticipo e ha funzionato come previsto, quindi apprezzerei la tua spiegazione.
Sara Fauzia,

Questo è il mio male, ho letto male la tua risposta. :-)
Chris Down

Come dovrei leggere il "${i#*.}"bit?
silente il

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.