cp si comporta stranamente quando. (punto) o .. (punto punto) sono la directory di origine


15

Questa risposta rivela che è possibile copiare tutti i file, inclusi quelli nascosti, dalla directorysrc alla directory in questo destmodo:

mkdir dest
cp -r src/. dest

Non vi è alcuna spiegazione nella risposta o nei suoi commenti sul perché questo effettivamente funziona, e nessuno sembra trovare documentazione su questo neanche.

Ho provato alcune cose. Innanzitutto, il caso normale:

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src dest
$ ls -A dest
dest_file  src

Quindi, con /.alla fine:

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src/. dest
$ ls -A dest
dest_file  .dotfile  src_dir  src_file

Quindi, questo si comporta in modo semplice *, ma copia anche i file nascosti.

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src/* dest
$ ls -A dest
dest_file  src_dir  src_file

.e ..sono hard-link come spiegato qui , proprio come la voce della directory stessa.

Da dove viene questo comportamento e dove è documentato?


3
Cosa intendi dire che nessuno può trovare la documentazione? Il cpriferimento spiega chiaramente come cp -Rfunziona. .e ..sono directory come qualsiasi altra directory, non c'è nulla di magico o misterioso in esse.
AlexP,

2
@AlexP Ho modificato la risposta per renderla più chiara. Il punto è che .e ..non si comportano come le altre directory.
iFreilicht,

Risposte:


27

Il comportamento è un risultato logico dell'algoritmo documentato per cp -R. Vedi POSIX , passaggio 2f:

I file nella directory source_file devono essere copiati nella directory dest_file , seguendo i quattro passaggi (da 1 a 4) elencati qui con i file come source_file .

.e ..sono directory, rispettivamente la directory corrente e la directory padre. Né sono speciali per quanto riguarda la shell, quindi non sono interessati dall'espansione e la directory verrà copiata includendo i file nascosti. *d'altra parte, verrà espanso in un elenco di file, ed è qui che vengono filtrati i file nascosti.

src/.è la directory corrente all'interno src, che è srcessa stessa; src/src_dir/..è src_dirla directory principale, che è di nuovo src. Quindi dall'esterno src, if srcè una directory, specificando src/.o src/src_dir/..come file sorgente per cpequivalenti, e copia il contenuto di src, compresi i file nascosti.

Il punto da specificare src/.è che fallirà se srcnon è una directory (o collegamento simbolico a una directory), mentre srcnon lo farebbe. Copierà anche il contenuto di srcsolo, senza copiare srcse stesso; questo corrisponde anche alla documentazione:

Se esiste una destinazione e nomina una directory esistente, il nome del percorso di destinazione corrispondente per ciascun file nella gerarchia dei file deve essere la concatenazione della destinazione , un singolo carattere barra se la destinazione non termina in una barra e il nome percorso del file relativo nella directory contenente source_file .

Quindi cp -R src/. destcopia il contenuto di srca dest/.(il file sorgente è .in src), mentre cp -R src destcopia il contenuto di srcadest/src (il file sorgente è src).

Un altro modo di pensare a questo è confrontare la copia src/src_dire src/., piuttosto che confrontare src/.e src. .si comporta proprio come src_dirnel primo caso.


Ma non si comporta allo stesso modo. Se si specifica srccopierà la directory in dest, src/.verranno copiati i contenuti. Proverò a renderlo più chiaro nella domanda.
iFreilicht,

Ecco, penso che risponda alla tua domanda di fondo.
Stephen Kitt,

1
@ Stéphane l'OP confronta la copia src/.e src/*(nota, non src/.* ); src/*non include file nascosti se il globbing li ignora ...
Stephen Kitt il

1
Hmm, "directory contenente source_file ". Bene, ovviamente srccontiene src/.ma significa che la directory contenente di una directory dipende da come si chiama la directory. Naturalmente l'esistenza dei .collegamenti in un certo senso significa che tutte le directory si contengono, ma ciò potrebbe non essere intuitivo per tutti. Invece di questo comportamento, si potrebbe anche essere tentati di presumere che "la directory contenente la directory foo" sarebbe determinata da foo/.., nel qual caso non importa se ci riferiamo a fooo foo/.: la directory contenente risultante sarebbe la stessa.
ilkkachu,

1
Vale a dire che la distinzione tra fooe foo/.sembra un po 'delicata, ma non mi dispiace, la trovo anche leggermente divertente.
ilkkachu,

1

Quando corri cp -R src/foo dest, otterrai dest/foo. Quindi, se la directory dest/foonon esiste, cpla creerà e quindi copierà il contenuto disrc/foo a dest/foo.

Quando corri cp -R src/. dest, cpvede che dest/.esiste, e quindi è solo questione di copiare il contenuto disrc/. a dest/..

Quando si pensa di esso come la copia di una directory chiamata .da srce fondere il contenuto con la directory esistente dest/., avrà senso.

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.