Copia l'elenco dei file


35

Ho un elenco di file separati da spazi in un file list.txt. Vorrei copiarli in una nuova cartella.

Ho provato a fare:

cp `cat list.txt` new_folder

ma non ha funzionato.

Come lo faresti ?

Aggiornare:

Grazie per tutte le tue risposte molto interessanti. Non ho chiesto molto :)

Dopo aver provato la soluzione sopra una seconda volta, sembra che sia stato cpstampato l'aiuto per l'uso perché la cartella new_foldernon esisteva ancora! Scusa, sembra essere uno stupido errore ... Quando creo la cartella prima, funziona.

Tuttavia, ho imparato molto da tutte le tue risposte e soluzioni, grazie per il tempo che dedichi a scriverle.


Vorrei chiarire una cosa: l'elenco ha tutti i nomi dei file su una riga, separati solo da uno spazio? O i nomi sono ciascuno su una riga separata?
Telemaco,

Tutto in un lime, separati da uno spazio. La soluzione di Doug ha funzionato :) Grazie per la risposta.
Klaus,

È divertente ... Ho testato la mia soluzione con una riga in cui ogni nome era su una riga separata.
Doug Harris,

"non ha funzionato" non è molto significativo. Esattamente come non ha funzionato. Funziona bene per me.
In pausa fino a nuovo avviso.

Ci dispiace: ha mostrato aiuto sull'uso di cp. Vedi il mio aggiornamento sopra.
Klaus,

Risposte:


34

Prova a usare xargs:

cat list.txt | xargs -J % cp % new_folder

Aggiornare:

L'ho fatto su OS X che ha una versione diversa rispetto alle versioni GNU / Linux. Quello xargsche proviene da GNU Findutils non ha, -Jma ha -Iquale è simile (come ha sottolineato Dennis Williamson in un commento). La versione OS X di xargs ha entrambi -Ie -Jche hanno comportamenti leggermente diversi: entrambi funzioneranno per questa domanda originale.

$ cat list.txt
one
two.txt
three.rtf

$ cat list.txt | xargs -J % echo cp % new_folder
cp one two.txt three.rtf new_folder

$ cat list.txt | xargs -I % echo cp % new_folder
cp one new_folder
cp two.txt new_folder
cp three.rtf new_folder

3
Il mio xargsnon ce -Jl'ha, -Iche sembra fare la stessa cosa. Quale versione di xargse quale sistema operativo / distribuzione hai?
In pausa fino a nuovo avviso.

Ho provato questo su Mac OS X 10.6 (aka snow leopard), quindi è qualunque versione di xargs fornita con il sistema operativo. In esecuzione xargs --versionrestituisce un messaggio di errore di utilizzo. È probabilmente una versione BSD di xargs. L'uso di -Ie -Jsono leggermente diversi. Aggiornerò la mia risposta con esempi ben formattati.
Doug Harris,

Sì, sto lavorando con Mac OSX 10.6. Grazie per le precisazioni su -Je -I:)
Klaus,

Questo è un buon consiglio per usare l'eco per controllare i tuoi comandi prima di eseguirli.
Liam,

1
Utilizzando lo stesso comando sopra solo con le modifiche necessarie, come posso copiare i file insieme alla creazione delle loro directory e sottodirectory in cui si trovano, separati da una barra?
Vicky Dev,

54

Non c'è bisogno di cataffatto:

xargs -a list.txt cp -t new_folder

O usando le opzioni lunghe:

xargs --arg-file=list.txt cp --target-directory=new_folder

Ecco alcune versioni della shell. Si noti che alcune variabili non sono quotate o i forloop sono utilizzati in modo specifico perché l'OP ha specificato che i nomi dei file sono delimitati da spazi. Alcune di queste tecniche non funzioneranno per l'input di nome file per riga in cui i nomi file contengono spazi bianchi.

bash:

for file in $(<list.txt); do cp "$file" new_folder; done

o

cp $(<list.txt) new_folder

sh (o Bash):

# still no cat!
while read -r line; do for file in $line; do cp "$file" new_folder; done; done < list.txt

o

# none here either
while read -r line; do cp $line new_folder; done < list.txt

o

# meow
for file in $(cat list.txt); do cp "$file" new_folder; done

o

# meow
cp $(cat list.txt) new_folder

domanda noob: perché è -tnecessario xargs -a list.txt cp -t new_folder?
Yibo Yang,

1
@YiboYang: -tè un'opzione di cp. Copia tutti gli argomenti di origine nella directory di destinazione specificata. Qui, consente di specificare la destinazione prima della fonte che viene aggiunta dal xargscomando.
In pausa fino a nuovo avviso.

Questo è utile ma cosa succede se list.txt contiene il percorso di cartelle e file misti? In tal caso il comando non funziona correttamente. Segnala "omettendo directory ..." e se -R è specificato al comando cp, l'errore "non è una directory" viene segnalato non appena si incontra il primo file nell'elenco.
Bemipefe,

7

Ho avuto una risposta imbarazzante intorno qui prima, ma la risposta di Denis mi ha ricordato che mi mancava la cosa più elementare. Quindi, ho eliminato la mia risposta originale. Ma dal momento che nessuno ha detto questa cosa molto semplice, penso che valga la pena metterlo qui.

La domanda originale è "Ho un file di testo con un elenco di nomi di file separati da spazi. Come posso copiarli in una directory di destinazione." All'inizio questo può sembrare complicato o complicato, perché pensi di dover in qualche modo estrarre gli elementi dal file in un modo specifico. Tuttavia, quando la shell elabora una riga di comando, la prima cosa che fa è separare l'elenco degli argomenti in token e (ecco il bit che nessuno ha mai detto apertamente) spazi token separati . (Newline inoltre separano i token, motivo per cui il test di Doug Harris con un elenco separato da una nuova riga ha avuto lo stesso risultato.) Cioè, la shell si aspetta e può già gestire un elenco separato da spazi.

Quindi tutto ciò che devi fare qui è mettere l'elenco separato da spazi (che hai già) nel posto giusto nel tuo comando. Il tuo comando è una variazione su questo:

cp file1 file2 file3...file# target

L'unica ruga è che vuoi ottenere l'elenco dei file da 1 a # dal tuo file di testo.

Come sottolinea Dennis nel suo commento, il tuo tentativo originale ( cpcat list.txt new_folder) avrebbe dovuto funzionare già. Perché? Perché il comando interno cat list.txtviene elaborato per primo dalla shell e si espande file1 file2 file3...file#, che è esattamente ciò che la shell si aspetta e vuole da quella parte del comando. Se non ha funzionato, allora (1) hai avuto un refuso o (2) i tuoi nomi di file erano in qualche modo strani (avevano spazi o altri caratteri insoliti).

Il motivo per cui tutte le risposte di Dennis funzionano è semplicemente che forniscono l'elenco necessario di file su cui cplavorare, posizionando tale elenco nel punto in cui appartiene all'intero comando. Ancora una volta, il comando stesso è questo nella struttura:

cp list-of-files target_directory

È facile vedere come tutto si combina in questa versione:

cp $(<list.txt) new_folder

$()fa sì che la shell esegua il comando tra parentesi e quindi sostituisca il suo output in quel punto nella linea più grande. Quindi la shell esegue la linea nel suo insieme. A proposito, $()è una versione più moderna di quello che stavi già facendo con i backtick (`). Next: <è un operatore di reindirizzamento dei file. Indica alla shell di scaricare il contenuto list.txtdell'input standard. Poiché il $()bit viene elaborato per primo, ecco cosa succede nelle fasi:

  1. cp $(<list.txt) new_folder # split line into three tokens: cp, $(<list.txt), new_folder
  2. cp file1 file2 file3...file# new_folder # substitute result of $(<list.txt) into the larger command

Ovviamente il passaggio 2 è semplicemente il normale cpcomando desiderato.

Mi rendo conto che sto battendo molto questo cavallo (forse molto morto), ma penso che valga la pena farlo. Comprendere esattamente come la shell elabora un comando può aiutarti a scriverlo meglio e semplificare molto. Ti mostrerà anche dove è probabile che i problemi si nascondano. In questo caso, ad esempio, la mia prima domanda per te avrebbe dovuto riguardare nomi di file divertenti o un possibile errore di battitura. Non erano necessarie acrobazie.


@Klaus Prego. Ad essere sincero, ero per lo più infastidito da me stesso dopo aver letto la risposta di Dennis e aver realizzato che mi mancava completamente la parte chiave del problema. La soluzione che ti piace viene anche da lì.
Telemaco,

Questa è una risposta super vecchia, ma se è necessario ricreare la struttura delle cartelle, è necessario il --parentsflag. Puoi renderlo dettagliato con -vuna registrazione di ciò che è stato copiato. Se si desidera mantenere le autorizzazioni, è necessario il flag -ao -p. Vale a dire, cp --parents -av $(<list.txt) new_folder. Tutto questo presuppone che il tuo elenco di file sia in realtà tutti i file, altrimenti potresti anche aver bisogno del -rflag per ricorrere.
Dhaupin,

@dhaupin In realtà, l'OP afferma di essere su macOS. Quindi per quello che vale, la --parentsbandiera non esiste lì. La loro versione (derivata da BSD) cpfornisce solo opzioni brevi, non opzioni lunghe in stile GNU. Per uno stile BSD cp, il flag per la copia ricorsiva è maiuscolo -R, non minuscolo.
Telemaco,
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.