Come si spostano tutti i file (incluso nascosto) da una directory a un'altra?


135

Come posso spostare tutti i file in una directory (compresi quelli nascosti) in un'altra directory?

Ad esempio, se ho una cartella "Foo" con i file ".hidden" e "notHidden" all'interno, come posso spostare entrambi i file in una directory denominata "Bar"? Quanto segue non funziona, poiché il file ".hidden" rimane in "Foo".

mv Foo/* Bar/

Prova tu stesso.

mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/


Bah, sapevo che avrei dovuto aggiornare le risposte prima di scrivere le mie. Link molto utile.
Steven D,

Purtroppo, questa domanda è finita qui perché ho detto su SO che dovrebbe spostarsi qui o SU, quindi ovviamente si è spostata qui quando c'era già un duplicato su SU :)
Michael Mrozek

Personalmente, penso che * nix domande e risposte specifiche dovrebbero essere fuori tema su SU. Con le regole attuali finiamo con tonnellate di collisioni di contenuti tra i due - come questa domanda.
Cory Klein,

Risposte:


154

zsh

mv Foo/*(DN) Bar/

o

setopt -s glob_dots
mv Foo/*(N) Bar/

(Lasciare fuori (N)se si sa che la directory non è vuota.)

bash

shopt -s dotglob nullglob
mv Foo/* Bar/

ksh93

Se sai che la directory non è vuota:

FIGNORE='.?(.)'
mv Foo/* Bar/

Standard (POSIX) sh

for x in Foo/* Foo/.[!.]* Foo/..?*; do
  if [ -e "$x" ]; then mv -- "$x" Bar/; fi
done

Se sei disposto a lasciare che il mvcomando restituisca uno stato di errore anche se è riuscito, è molto più semplice:

mv Foo/* Foo/.[!.]* Foo/..?* Bar/

GNU find e GNU mv

find Foo/ -mindepth 1 -maxdepth 1 -exec mv -t Bar/ -- {} +

Trova standard

Se non ti dispiace cambiare nella directory di origine:

cd Foo/ &&
find . -name . -o -exec sh -c 'mv -- "$@" "$0"' ../Bar/ {} + -type d -prune

Ecco ulteriori dettagli sul controllo della corrispondenza dei file dot in bash, ksh93 e zsh.

bash

Imposta l' dotglobopzione .

$ echo *
none zero
$ shopt -s dotglob
$ echo *
..two .one none zero

C'è anche la GLOBIGNOREvariabile più flessibile , che è possibile impostare su un elenco separato da due punti di motivi jolly da ignorare. Se non impostato (impostazione predefinita), la shell si comporta come se il valore fosse vuoto se dotglobimpostato, e come se il valore fosse .*se l'opzione non è impostata. Vedere Espansione nome file nel manuale. Le directory pervasive .e ..sono sempre omesse, a meno che non .sia abbinato esplicitamente al modello.

$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one

ksh93

Imposta la FIGNOREvariabile . Se non impostato (impostazione predefinita), la shell si comporta come se il valore fosse .*. Per ignorarli .e .., devono essere abbinati esplicitamente (il manuale in ksh 93s + 2008-01-31 afferma che .e ..sono sempre ignorati, ma questo non descrive correttamente il comportamento reale).

$ echo *
none zero
$ FIGNORE='@(.|..)'
$ echo *
..two .one none zero
$ FIGNORE='n*'
$ echo *
. .. ..two .one zero

È possibile includere file di punti in un modello abbinandoli esplicitamente.

$ unset FIGNORE
$ echo @(*|.[^.]*|..?*)
..two .one none zero

Per fare in modo che l'espansione risulti vuota se la directory è vuota, utilizzare l' Nopzione di corrispondenza del modello: ~(N)@(*|.[^.]*|..?*)o ~(N:*|.[^.]*|..?*).

zsh

Imposta l' dot_globopzione .

% echo *
none zero
% setopt dot_glob
% echo *
..two .one none zero

.e ..non vengono mai abbinati, anche se lo schema corrisponde .esplicitamente al comando iniziale.

% echo .*
..two .one

È possibile includere file dot in uno schema specifico con il D qualificatore glob .

% echo *(D)
..two .one none zero

Aggiungere il Nqualificatore glob per rendere l'espansione uscirà vuota in una directory vuota: *(DN).


Nota: è possibile ottenere risultati espansione dei nomi in ordine diverso (ad esempio, noneseguita da .oneseguita da ..two) in base alle impostazioni dei LC_COLLATE, LC_ALLe LANGle variabili.


1
Perché nullglob? Avrebbe più senso interrompere il mvcomando (come fish, csh / tcsh, zsh (senza (N)) do, o bash con failglob) che eseguire un mv /Bar/comando che ha poco senso.
Stéphane Chazelas,

1
Direi che la tua descrizione GLOBIGNORE è inaccurata e fuorviante. L'impostazione di GLOBIGNORE su un valore non vuoto attiva dotglob e lo rende .e ..non viene mai abbinato (come in altre conchiglie sensibili come zsh, fish, pdksh e derivati) anche se successivamente si ripristina dotglob. ( GLOBIGNORE=:; shopt -u dotglob; echo .*non verrà emesso .e ..). impostando GLOBIGNORE su .:..o .o :avere lo stesso effetto.
Stéphane Chazelas,

ksh93ignorando sempre .e ..sembra essere stato interrotto tra ksh93k+(dove ha funzionato) e ksh93m(dove non funziona più). Si noti che è un male in quanto ksh93prenderà il valore di FIGNORE dall'ambiente, quindi un FIGNORE='!(..)'var ad esempio può creare il caos.
Stéphane Chazelas,

24
#!/bin/bash

shopt -s dotglob
mv Foo/* Bar/

A partire dal man bash

dotglob Se impostato, bash include i nomi di file che iniziano con un '.' nei risultati dell'espansione del nome percorso.


Con l'avvertenza che questo comando restituisce un codice di errore se la directory era vuota (anche se il comando effettivamente eseguito come previsto).
Gilles,

1
@Gilles, l'errore sarà dovuto al mvlamentarsi che quel file chiamato Foo/*non esiste. È interessante notare che, se Fooè ricercabile, ma non leggibile, e c'è un file chiamato *lì, non otterrai errori, quel file verrà spostato, ma non gli altri nella directory. bashha failglobun'opzione in modo che si comporti più come zsh, fisho csh/ tcshe annulla il comando con un errore quando un glob non può essere espanso invece di quel comportamento fasullo di lasciare il glob così com'è.
Stéphane Chazelas,

8

Un modo semplice per farlo bashè

mv {Foo/*,Foo/.*} Bar/

Ma questo sposterà anche le directory.

Se si desidera spostare tutti i file inclusi quelli nascosti ma non si desidera spostare alcuna directory, è possibile utilizzare un ciclo for e test.

for i in $(ls -d {Foo/*,Foo/.*});do test -f $i && mv -v $i Bar/; done;


4

Un modo è usare find:

find Foo/ -type f -exec mv -t Bar/ {} \+

La -type flimita il comando find per la ricerca di file. Si dovrebbe indagare il -type, -maxdepth, e le -mindepthopzioni di findper personalizzare il vostro comando per tenere conto di sottodirectory. Trova ha una pagina di manuale lunga ma molto utile .


3
Ciò sposta solo i file normali Foo/, non le sottodirectory e altri file.
Gilles,

2

Prova il comando copia cp:

$ cp -r myfolder/* destinationfolder

cp -r significa copia ricorsiva, quindi verranno copiate tutte le cartelle e i file.

È possibile utilizzare il comando rmremove per rimuovere una cartella:

$ rm -r myfolder

Vedi di più: sposta tutti i file da una directory a un'altra .


2
Non è il migliore quando si spostano molti file di grandi dimensioni, ma immagino che funzionerebbe.
Cory Klein,

Forse se usi un punto anziché la stella?
vincent

1

Rsync è un'altra opzione:

rsync -axvP --remove-source-files sourcedirectory/ targetdirectory

Questo funziona perché in rsync la barra finale è importante, si sourcedirectory/riferisce al contenuto della directory, mentre sourcedirectoryfarebbe riferimento alla directory stessa.

Lo svantaggio di questo metodo è che rsync pulirà i file solo dopo lo spostamento, non la directory. Quindi ti rimane un albero di directory di provenienza vuoto. Per soluzioni alternative, vedere:

Spostare i file ed eliminare le directory con rsync?

Pertanto, sebbene ciò non sia ottimale per le operazioni di spostamento, può essere estremamente utile per le operazioni di copia.


1

Risposta per bash / pesce

Ecco un modo per farlo usando i caratteri jolly:

.[!.]* ..?*corrisponderà a tutti i file nascosti tranne .e..

.[!.]* ..?* *corrisponderà a tutti i file (nascosti o meno) tranne .e..

E per rispondere all'esempio particolare di questa domanda è necessario cd foo && mv .[!.]* ..?* * ../bar

Spiegazione

.[!.]*corrisponde a nomi di file che iniziano con un punto, seguito da qualsiasi carattere tranne il punto facoltativamente seguito da qualsiasi stringa. Questo è abbastanza vicino ma manca i file che iniziano con due punti come ..foo. Per includere tali file aggiungiamo ..?*che corrisponde a nomi di file che iniziano con due punti, seguiti da qualsiasi carattere, facoltativamente seguito da qualsiasi stringa.

Test

È possibile testare questi caratteri jolly con i comandi seguenti. Li ho provati con successo sotto bash e pesce. Falliscono sotto sh, zsh, xonsh.

mkdir temp
cd temp
touch  a  .b  .bc  ..c  ..cd  ...d  ...de
ls .[!.]* ..?*
# you get this output:
          .b  .bc  ..c  ..cd  ...d  ...de
# cleanup
cd ..
rm -rf temp

0

Potresti anche essere in grado di trovare e grep con backquotes per selezionare i file per il comando move. Passa quelli in mv.

Vale a dire per i file nascosti

find Foo -maxdepth 1 | egrep '^Foo/[.]' # Output: .hidden

Così

mv `find Foo -maxdepth 1 | egrep '^Foo/[.]'` Bar # mv Foo/.hidden Bar

Sposta solo i file nascosti selezionati in Bar:

mv `find Foo -maxdepth 1 | egrep '^Foo/.'` Bar # mv Foo/.hidden Foo/notHidden Bar

Sposta tutti i file in Foo su Bar dal '.' nel comando egrep funge da carattere jolly senza parentesi quadre.

Il ^personaggio si assicura che la partita inizi dall'inizio della linea.

Alcuni dettagli sulla egrepcorrispondenza dei motivi sono disponibili qui .

L'uso di maxdepth 1stop trova da andare nelle sottodirectory.


0

Ispirato da questa risposta :

Senza copiare i file ...

rsync -ax --link-dest=../Foo/ Foo/ Bar

Avvertenze:

  • --link-destil percorso deve essere assoluto o relativo a DESTINATION ( Bar nell'esempio)

  • Devi inserire /SOURCE ( Foo/nell'esempio), altrimenti copierà la cartella SOURCE invece del suo contenuto.


0

Trovo che questo funzioni bene per bash e non c'è bisogno di cambiare le opzioni della shell

mv sourcedir/{*,.[^.]*} destdir/

MODIFICARE:

Quindi, come ha affermato G-man, la mia risposta originale non è conforme a posix ed è praticamente la stessa della risposta di ndemou sopra con una modifica, che è quella di utilizzare l'espansione del rinforzo per creare elenchi di stringhe su cui si agisce. Questo significa solo che non è necessario cdaccedere alla directory di origine. Non è un grande cambiamento, ma è diverso.

esempio: supponiamo che tu abbia già il seguente layout.

 $ tree -a
.
├── destdir
└── sourcedir
    ├── ..d1
    ├── ..d2
    ├── ..double
    ├── file-1
    ├── file-2
    ├── .hidden-1
    ├── .hidden-2
    ├── ...t1
    └── ...t2

La domanda originale menzionava solo i file nascosti con un singolo punto, ma supponiamo che ci siano alcuni con due o più punti all'inizio del nome. Puoi semplicemente aggiungere un'espressione aggiuntiva tra parentesi graffe. Possiamo quindi eseguire

mv sourcedir/{*,.[!.]*,..?*} destdir/

Questo viene espanso come segue:

mv sourcedir/file-1 sourcedir/file-2 sourcedir/.hidden-1 sourcedir/.hidden-2 sourcedir/..d1 sourcedir/..d2 sourcedir/..double sourcedir/...t1 sourcedir/...t2 destdir/

Ora dovresti vedere tutti i file che si trovano in destdir :

 $ tree -a
.
├── destdir
   ├── ..d1
   ├── ..d2
   ├── ..double
   ├── file-1
   ├── file-2
   ├── .hidden-1
   ├── .hidden-2
   ├── ...t1
   └── ...t2
└── sourcedir

Puoi fare cose piuttosto interessanti con parentesi graffe in bash con ancora più aggiunte in 4.x. Dai un'occhiata a bash-hacker per alcuni esempi ingegnosi.


1
Questo sostanzialmente duplica la risposta di ndemou, tranne per il fatto che hai aggiunto parentesi graffe (senza spiegarle). Ma (1) la tua risposta non corrisponde ai file i cui nomi iniziano con .., e (2) per essere conforme a POSIX , dovresti usare !invece di ^; Per esempio,  {*,.[!.]*}.
G-Man il

@ G-Man, mi dispiace per quello. Quindi hai ragione e il mio male per non aver visto la risposta di ndemou. Sono praticamente la stessa cosa. 1. grazie per aver sottolineato che la mia versione non è conforme a posix. 2. Sto usando l'espansione del controvento per creare elenchi di stringhe che la shell utilizzerà per eseguire un'azione. Questo significa anche che non ho bisogno di cdaccedere alla directory dei sorgenti per agire sui file o scrivere ripetutamente gli stessi percorsi dei file per esprimere i percorsi a tutti i file. Presto aggiornerò l'esempio per dare a tutti i lettori un'immagine migliore di ciò di cui sto parlando.
cmndr sp0ck

0

Per distribuzioni Linux minime , dovrebbe funzionare come segue. Innanzitutto, esegui una mossa di base tutto (che manca i file nascosti). Quindi, sposta tutti i file nascosti (incluso il .e ..che non verranno effettivamente spostati).

mv /sourceDir/* /destinationDir 2> /dev/null
mv /sourceDir/.* /destinationDir 2> /dev/null

Note: se non è presente alcun contenuto visibile, il primo comando produrrà un messaggio di errore. Il secondo comando produrrà sempre un errore che dice che non può muoversi .e ... Pertanto, inserisci gli errori /dev/null(come mostrato).

Se hai bisogno di questo come un liner, basta combinarli con un punto e virgola:

mv /sourceDir/* /destinationDir 2> /dev/null; mv /sourceDir/.* /destinationDir 2> /dev/null
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.