cp behaves weirdly when . (dot) or .. (dot dot) are the source directory












11















This answer reveals that one can copy all files - including hidden ones - from directory src into directory dest like so:



mkdir dest
cp -r src/. dest


There is no explanation in the answer or its comments as to why this actually works, and nobody seems to find documentation on this either.



I tried out a few things. First, the normal case:



$ 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


Then, with /. at the end:



$ 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


So, this behaves simlarly to *, but also copies hidden files.



$ 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


. and .. are proper hard-links as explained here, just like the directory entry itself.



Where does this behaviour come from, and where is it documented?










share|improve this question




















  • 3





    What do you mean nobody can find documentation? The cp reference clearly explains how cp -R works. . and .. are directories just like any other directories, there is nothing magical or mysterious about them.

    – AlexP
    Dec 6 '17 at 14:58






  • 2





    @AlexP I edited the answer to make it clearer. The whole point is that . and .. don't behave like other directories.

    – iFreilicht
    Dec 6 '17 at 15:07
















11















This answer reveals that one can copy all files - including hidden ones - from directory src into directory dest like so:



mkdir dest
cp -r src/. dest


There is no explanation in the answer or its comments as to why this actually works, and nobody seems to find documentation on this either.



I tried out a few things. First, the normal case:



$ 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


Then, with /. at the end:



$ 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


So, this behaves simlarly to *, but also copies hidden files.



$ 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


. and .. are proper hard-links as explained here, just like the directory entry itself.



Where does this behaviour come from, and where is it documented?










share|improve this question




















  • 3





    What do you mean nobody can find documentation? The cp reference clearly explains how cp -R works. . and .. are directories just like any other directories, there is nothing magical or mysterious about them.

    – AlexP
    Dec 6 '17 at 14:58






  • 2





    @AlexP I edited the answer to make it clearer. The whole point is that . and .. don't behave like other directories.

    – iFreilicht
    Dec 6 '17 at 15:07














11












11








11


5






This answer reveals that one can copy all files - including hidden ones - from directory src into directory dest like so:



mkdir dest
cp -r src/. dest


There is no explanation in the answer or its comments as to why this actually works, and nobody seems to find documentation on this either.



I tried out a few things. First, the normal case:



$ 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


Then, with /. at the end:



$ 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


So, this behaves simlarly to *, but also copies hidden files.



$ 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


. and .. are proper hard-links as explained here, just like the directory entry itself.



Where does this behaviour come from, and where is it documented?










share|improve this question
















This answer reveals that one can copy all files - including hidden ones - from directory src into directory dest like so:



mkdir dest
cp -r src/. dest


There is no explanation in the answer or its comments as to why this actually works, and nobody seems to find documentation on this either.



I tried out a few things. First, the normal case:



$ 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


Then, with /. at the end:



$ 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


So, this behaves simlarly to *, but also copies hidden files.



$ 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


. and .. are proper hard-links as explained here, just like the directory entry itself.



Where does this behaviour come from, and where is it documented?







cp recursive hard-link documentation dot-files






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 6 '17 at 15:06







iFreilicht

















asked Dec 6 '17 at 14:40









iFreilichtiFreilicht

21018




21018








  • 3





    What do you mean nobody can find documentation? The cp reference clearly explains how cp -R works. . and .. are directories just like any other directories, there is nothing magical or mysterious about them.

    – AlexP
    Dec 6 '17 at 14:58






  • 2





    @AlexP I edited the answer to make it clearer. The whole point is that . and .. don't behave like other directories.

    – iFreilicht
    Dec 6 '17 at 15:07














  • 3





    What do you mean nobody can find documentation? The cp reference clearly explains how cp -R works. . and .. are directories just like any other directories, there is nothing magical or mysterious about them.

    – AlexP
    Dec 6 '17 at 14:58






  • 2





    @AlexP I edited the answer to make it clearer. The whole point is that . and .. don't behave like other directories.

    – iFreilicht
    Dec 6 '17 at 15:07








3




3





What do you mean nobody can find documentation? The cp reference clearly explains how cp -R works. . and .. are directories just like any other directories, there is nothing magical or mysterious about them.

– AlexP
Dec 6 '17 at 14:58





What do you mean nobody can find documentation? The cp reference clearly explains how cp -R works. . and .. are directories just like any other directories, there is nothing magical or mysterious about them.

– AlexP
Dec 6 '17 at 14:58




2




2





@AlexP I edited the answer to make it clearer. The whole point is that . and .. don't behave like other directories.

– iFreilicht
Dec 6 '17 at 15:07





@AlexP I edited the answer to make it clearer. The whole point is that . and .. don't behave like other directories.

– iFreilicht
Dec 6 '17 at 15:07










1 Answer
1






active

oldest

votes


















22














The behaviour is a logical result of the documented algorithm for cp -R. See POSIX, step 2f:




The files in the directory source_file shall be copied to the directory dest_file, taking the four steps (1 to 4) listed here with the files as source_files.




. and .. are directories, respectively the current directory, and the parent directory. Neither are special as far as the shell is concerned, so neither are concerned by expansion, and the directory will be copied including hidden files. *, on the other hand, will be expanded to a list of files, and this is where hidden files are filtered out.



src/. is the current directory inside src, which is src itself; src/src_dir/.. is src_dir’s parent directory, which is again src. So from outside src, if src is a directory, specifying src/. or src/src_dir/.. as the source file for cp are equivalent, and copy the contents of src, including hidden files.



The point of specifying src/. is that it will fail if src is not a directory (or symbolic link to a directory), whereas src wouldn’t. It will also copy the contents of src only, without copying src itself; this matches the documentation too:




If target exists and names an existing directory, the name of the corresponding destination
path for each file in the file hierarchy shall be the concatenation of target, a single slash
character if target did not end in a slash, and the pathname of the file relative to the
directory containing source_file.




So cp -R src/. dest copies the contents of src to dest/. (the source file is . in src), whereas cp -R src dest copies the contents of src to dest/src (the source file is src).



Another way to think of this is to compare copying src/src_dir and src/., rather than comparing src/. and src. . behaves just like src_dir in the former case.






share|improve this answer


























  • But it doesn't behave the same way. Specifying src will copy the directory into dest, src/. will copy the contents. I'll try to make that clearer in the question.

    – iFreilicht
    Dec 6 '17 at 14:59











  • There, I think that answers your underlying question.

    – Stephen Kitt
    Dec 6 '17 at 15:07











  • Not sure what you mean by so neither are concerned by expansion (which avoids issues with the shell expanding hidden files or not). cp -r src/.* dest/ is a problem in shells like bash that don't remove . and .. from their globs (fixed in zsh, fish, pdksh (from the Forsyth shell) and derivatives).

    – Stéphane Chazelas
    Dec 6 '17 at 15:22








  • 1





    @Stéphane the OP compares copying src/. and src/* (note, not src/.*); src/* doesn’t include hidden files if globbing ignores them...

    – Stephen Kitt
    Dec 6 '17 at 15:23











  • Ah OK. Note that yash -o dotglob -c 'echo *' does include . and ... * can include . and .. as well in ksh depending on how you configure FIGNORE.

    – Stéphane Chazelas
    Dec 6 '17 at 15:27











Your Answer








StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f409225%2fcp-behaves-weirdly-when-dot-or-dot-dot-are-the-source-directory%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









22














The behaviour is a logical result of the documented algorithm for cp -R. See POSIX, step 2f:




The files in the directory source_file shall be copied to the directory dest_file, taking the four steps (1 to 4) listed here with the files as source_files.




. and .. are directories, respectively the current directory, and the parent directory. Neither are special as far as the shell is concerned, so neither are concerned by expansion, and the directory will be copied including hidden files. *, on the other hand, will be expanded to a list of files, and this is where hidden files are filtered out.



src/. is the current directory inside src, which is src itself; src/src_dir/.. is src_dir’s parent directory, which is again src. So from outside src, if src is a directory, specifying src/. or src/src_dir/.. as the source file for cp are equivalent, and copy the contents of src, including hidden files.



The point of specifying src/. is that it will fail if src is not a directory (or symbolic link to a directory), whereas src wouldn’t. It will also copy the contents of src only, without copying src itself; this matches the documentation too:




If target exists and names an existing directory, the name of the corresponding destination
path for each file in the file hierarchy shall be the concatenation of target, a single slash
character if target did not end in a slash, and the pathname of the file relative to the
directory containing source_file.




So cp -R src/. dest copies the contents of src to dest/. (the source file is . in src), whereas cp -R src dest copies the contents of src to dest/src (the source file is src).



Another way to think of this is to compare copying src/src_dir and src/., rather than comparing src/. and src. . behaves just like src_dir in the former case.






share|improve this answer


























  • But it doesn't behave the same way. Specifying src will copy the directory into dest, src/. will copy the contents. I'll try to make that clearer in the question.

    – iFreilicht
    Dec 6 '17 at 14:59











  • There, I think that answers your underlying question.

    – Stephen Kitt
    Dec 6 '17 at 15:07











  • Not sure what you mean by so neither are concerned by expansion (which avoids issues with the shell expanding hidden files or not). cp -r src/.* dest/ is a problem in shells like bash that don't remove . and .. from their globs (fixed in zsh, fish, pdksh (from the Forsyth shell) and derivatives).

    – Stéphane Chazelas
    Dec 6 '17 at 15:22








  • 1





    @Stéphane the OP compares copying src/. and src/* (note, not src/.*); src/* doesn’t include hidden files if globbing ignores them...

    – Stephen Kitt
    Dec 6 '17 at 15:23











  • Ah OK. Note that yash -o dotglob -c 'echo *' does include . and ... * can include . and .. as well in ksh depending on how you configure FIGNORE.

    – Stéphane Chazelas
    Dec 6 '17 at 15:27
















22














The behaviour is a logical result of the documented algorithm for cp -R. See POSIX, step 2f:




The files in the directory source_file shall be copied to the directory dest_file, taking the four steps (1 to 4) listed here with the files as source_files.




. and .. are directories, respectively the current directory, and the parent directory. Neither are special as far as the shell is concerned, so neither are concerned by expansion, and the directory will be copied including hidden files. *, on the other hand, will be expanded to a list of files, and this is where hidden files are filtered out.



src/. is the current directory inside src, which is src itself; src/src_dir/.. is src_dir’s parent directory, which is again src. So from outside src, if src is a directory, specifying src/. or src/src_dir/.. as the source file for cp are equivalent, and copy the contents of src, including hidden files.



The point of specifying src/. is that it will fail if src is not a directory (or symbolic link to a directory), whereas src wouldn’t. It will also copy the contents of src only, without copying src itself; this matches the documentation too:




If target exists and names an existing directory, the name of the corresponding destination
path for each file in the file hierarchy shall be the concatenation of target, a single slash
character if target did not end in a slash, and the pathname of the file relative to the
directory containing source_file.




So cp -R src/. dest copies the contents of src to dest/. (the source file is . in src), whereas cp -R src dest copies the contents of src to dest/src (the source file is src).



Another way to think of this is to compare copying src/src_dir and src/., rather than comparing src/. and src. . behaves just like src_dir in the former case.






share|improve this answer


























  • But it doesn't behave the same way. Specifying src will copy the directory into dest, src/. will copy the contents. I'll try to make that clearer in the question.

    – iFreilicht
    Dec 6 '17 at 14:59











  • There, I think that answers your underlying question.

    – Stephen Kitt
    Dec 6 '17 at 15:07











  • Not sure what you mean by so neither are concerned by expansion (which avoids issues with the shell expanding hidden files or not). cp -r src/.* dest/ is a problem in shells like bash that don't remove . and .. from their globs (fixed in zsh, fish, pdksh (from the Forsyth shell) and derivatives).

    – Stéphane Chazelas
    Dec 6 '17 at 15:22








  • 1





    @Stéphane the OP compares copying src/. and src/* (note, not src/.*); src/* doesn’t include hidden files if globbing ignores them...

    – Stephen Kitt
    Dec 6 '17 at 15:23











  • Ah OK. Note that yash -o dotglob -c 'echo *' does include . and ... * can include . and .. as well in ksh depending on how you configure FIGNORE.

    – Stéphane Chazelas
    Dec 6 '17 at 15:27














22












22








22







The behaviour is a logical result of the documented algorithm for cp -R. See POSIX, step 2f:




The files in the directory source_file shall be copied to the directory dest_file, taking the four steps (1 to 4) listed here with the files as source_files.




. and .. are directories, respectively the current directory, and the parent directory. Neither are special as far as the shell is concerned, so neither are concerned by expansion, and the directory will be copied including hidden files. *, on the other hand, will be expanded to a list of files, and this is where hidden files are filtered out.



src/. is the current directory inside src, which is src itself; src/src_dir/.. is src_dir’s parent directory, which is again src. So from outside src, if src is a directory, specifying src/. or src/src_dir/.. as the source file for cp are equivalent, and copy the contents of src, including hidden files.



The point of specifying src/. is that it will fail if src is not a directory (or symbolic link to a directory), whereas src wouldn’t. It will also copy the contents of src only, without copying src itself; this matches the documentation too:




If target exists and names an existing directory, the name of the corresponding destination
path for each file in the file hierarchy shall be the concatenation of target, a single slash
character if target did not end in a slash, and the pathname of the file relative to the
directory containing source_file.




So cp -R src/. dest copies the contents of src to dest/. (the source file is . in src), whereas cp -R src dest copies the contents of src to dest/src (the source file is src).



Another way to think of this is to compare copying src/src_dir and src/., rather than comparing src/. and src. . behaves just like src_dir in the former case.






share|improve this answer















The behaviour is a logical result of the documented algorithm for cp -R. See POSIX, step 2f:




The files in the directory source_file shall be copied to the directory dest_file, taking the four steps (1 to 4) listed here with the files as source_files.




. and .. are directories, respectively the current directory, and the parent directory. Neither are special as far as the shell is concerned, so neither are concerned by expansion, and the directory will be copied including hidden files. *, on the other hand, will be expanded to a list of files, and this is where hidden files are filtered out.



src/. is the current directory inside src, which is src itself; src/src_dir/.. is src_dir’s parent directory, which is again src. So from outside src, if src is a directory, specifying src/. or src/src_dir/.. as the source file for cp are equivalent, and copy the contents of src, including hidden files.



The point of specifying src/. is that it will fail if src is not a directory (or symbolic link to a directory), whereas src wouldn’t. It will also copy the contents of src only, without copying src itself; this matches the documentation too:




If target exists and names an existing directory, the name of the corresponding destination
path for each file in the file hierarchy shall be the concatenation of target, a single slash
character if target did not end in a slash, and the pathname of the file relative to the
directory containing source_file.




So cp -R src/. dest copies the contents of src to dest/. (the source file is . in src), whereas cp -R src dest copies the contents of src to dest/src (the source file is src).



Another way to think of this is to compare copying src/src_dir and src/., rather than comparing src/. and src. . behaves just like src_dir in the former case.







share|improve this answer














share|improve this answer



share|improve this answer








edited 14 mins ago









iFreilicht

21018




21018










answered Dec 6 '17 at 14:49









Stephen KittStephen Kitt

172k24386464




172k24386464













  • But it doesn't behave the same way. Specifying src will copy the directory into dest, src/. will copy the contents. I'll try to make that clearer in the question.

    – iFreilicht
    Dec 6 '17 at 14:59











  • There, I think that answers your underlying question.

    – Stephen Kitt
    Dec 6 '17 at 15:07











  • Not sure what you mean by so neither are concerned by expansion (which avoids issues with the shell expanding hidden files or not). cp -r src/.* dest/ is a problem in shells like bash that don't remove . and .. from their globs (fixed in zsh, fish, pdksh (from the Forsyth shell) and derivatives).

    – Stéphane Chazelas
    Dec 6 '17 at 15:22








  • 1





    @Stéphane the OP compares copying src/. and src/* (note, not src/.*); src/* doesn’t include hidden files if globbing ignores them...

    – Stephen Kitt
    Dec 6 '17 at 15:23











  • Ah OK. Note that yash -o dotglob -c 'echo *' does include . and ... * can include . and .. as well in ksh depending on how you configure FIGNORE.

    – Stéphane Chazelas
    Dec 6 '17 at 15:27



















  • But it doesn't behave the same way. Specifying src will copy the directory into dest, src/. will copy the contents. I'll try to make that clearer in the question.

    – iFreilicht
    Dec 6 '17 at 14:59











  • There, I think that answers your underlying question.

    – Stephen Kitt
    Dec 6 '17 at 15:07











  • Not sure what you mean by so neither are concerned by expansion (which avoids issues with the shell expanding hidden files or not). cp -r src/.* dest/ is a problem in shells like bash that don't remove . and .. from their globs (fixed in zsh, fish, pdksh (from the Forsyth shell) and derivatives).

    – Stéphane Chazelas
    Dec 6 '17 at 15:22








  • 1





    @Stéphane the OP compares copying src/. and src/* (note, not src/.*); src/* doesn’t include hidden files if globbing ignores them...

    – Stephen Kitt
    Dec 6 '17 at 15:23











  • Ah OK. Note that yash -o dotglob -c 'echo *' does include . and ... * can include . and .. as well in ksh depending on how you configure FIGNORE.

    – Stéphane Chazelas
    Dec 6 '17 at 15:27

















But it doesn't behave the same way. Specifying src will copy the directory into dest, src/. will copy the contents. I'll try to make that clearer in the question.

– iFreilicht
Dec 6 '17 at 14:59





But it doesn't behave the same way. Specifying src will copy the directory into dest, src/. will copy the contents. I'll try to make that clearer in the question.

– iFreilicht
Dec 6 '17 at 14:59













There, I think that answers your underlying question.

– Stephen Kitt
Dec 6 '17 at 15:07





There, I think that answers your underlying question.

– Stephen Kitt
Dec 6 '17 at 15:07













Not sure what you mean by so neither are concerned by expansion (which avoids issues with the shell expanding hidden files or not). cp -r src/.* dest/ is a problem in shells like bash that don't remove . and .. from their globs (fixed in zsh, fish, pdksh (from the Forsyth shell) and derivatives).

– Stéphane Chazelas
Dec 6 '17 at 15:22







Not sure what you mean by so neither are concerned by expansion (which avoids issues with the shell expanding hidden files or not). cp -r src/.* dest/ is a problem in shells like bash that don't remove . and .. from their globs (fixed in zsh, fish, pdksh (from the Forsyth shell) and derivatives).

– Stéphane Chazelas
Dec 6 '17 at 15:22






1




1





@Stéphane the OP compares copying src/. and src/* (note, not src/.*); src/* doesn’t include hidden files if globbing ignores them...

– Stephen Kitt
Dec 6 '17 at 15:23





@Stéphane the OP compares copying src/. and src/* (note, not src/.*); src/* doesn’t include hidden files if globbing ignores them...

– Stephen Kitt
Dec 6 '17 at 15:23













Ah OK. Note that yash -o dotglob -c 'echo *' does include . and ... * can include . and .. as well in ksh depending on how you configure FIGNORE.

– Stéphane Chazelas
Dec 6 '17 at 15:27





Ah OK. Note that yash -o dotglob -c 'echo *' does include . and ... * can include . and .. as well in ksh depending on how you configure FIGNORE.

– Stéphane Chazelas
Dec 6 '17 at 15:27


















draft saved

draft discarded




















































Thanks for contributing an answer to Unix & Linux Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f409225%2fcp-behaves-weirdly-when-dot-or-dot-dot-are-the-source-directory%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Loup dans la culture

How to solve the problem of ntp “Unable to contact time server” from KDE?

ASUS Zenbook UX433/UX333 — Configure Touchpad-embedded numpad on Linux