Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

(Update: this happens on Mac OS X -- I am using Mountain Lion.) It sometimes happen that I use the tab key to complete the path, so my command may be:

cp -r ~/some/folder/ .

but it turns out that the line above has a different behavior from

cp -r ~/some/folder .

the second line will copy the folder into the current directory, as folder, but the first line will copy all 7 files, 6 subfolders into the current directory, contaminating the current directory. Since I don't do any source control using git or svn in that particular current directory, it actually has to be cleaned up manually, and it is quite a pain.

Is there a way to prevent this from happening? Such as by making a function, alias, or Bash setting? I know I can remember this, but 2 months down the road, I can actually accidentally do the same thing again, so it is better to guard against this behavior. (I would rather needing to use cp -r ~/some/folder/* . and cp -r ~/some/folder/.* . if that is what I really want.)

share|improve this question
    
That behavior for the first example sounds strange and wrong and I am unable to reproduce it with GNU coreutils cp. What version / OS do you have? –  jw013 Nov 19 '12 at 15:31
1  
I was about to say my system does not behave this way. Neither on ubuntu on my laptop, centos server I control, or even cygwin at work.. –  Drake Clarris Nov 19 '12 at 15:36
    
Maybe he was really using rsync but changed it to cp for the question? –  jordanm Nov 19 '12 at 15:43
2  
It actually works this way on BSD/Mac OS. -R ... If the source_file ends in a /, the contents of the directory are copied rather than the directory itself. man cp 1 –  Mikel Nov 19 '12 at 15:59
    
yeah never tried a bsd flavor, so was not aware. Interesting to note, thanks! –  Drake Clarris Nov 19 '12 at 18:51

2 Answers 2

To do this right would require re-parsing all of cp's options, and that's not a good idea. But here's something that should come close:

# run cp command as-given, unless any argument ends in a slash
safecp() {
  for arg; do
    case $arg in */)
      echo "safecp: trailing slash in cp $*" >&2
      return 1
      ;;
    esac
  done
  cp "$@"
}

Alternatively, try putting

set mark-directories off

in your ~/.inputrc to make bash not automatically add a slash when tab-completing directories.

share|improve this answer
    
or can we make cp behave this way: if the source has a trailing /, then stop with a warning, so we actually need to use \cp or somehow bypass the function if that's what we desire. If there is no trailing / in the source, then just proceed with the usual cp. I think not adding slash when tab-completing could be quite troublesome because we need to add the slash ourselves each time if there are several levels down for a path. –  動靜能量 Nov 20 '12 at 20:39

You could certainly write a short bash function (with a recent version of bash, which can do regular expressions it's extremely simple), that would catch this kind of errors:

function cpr () {
    local src=...
    if [[ "$src" =~ /$ ]]; then
        # handle error
    else
        # proceed with copying
    fi 
}

the tricky part is determining what dest should be (you certainly want to skip the destination directory), if you want to cover all of cp's options combinations (at least the GNU coreutils' cp has 3 different variations of syntax).

Using a specialised function that would correct it in-place might be better:

function cpr () {
    cp -R ${1%%/} ${2}
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.