Thursday, September 19

A potential dangerous operation of "cp" command in linux

My ~/source/ folder has two files, "a" and "b". Now I am in ~/target/ folder and trying to copy 2 of them here:

~/target$ cp ../source/*

Yes I made a mistake. I intended to:
~/target$ cp ../source/* .

and I forgot the "." meaning to copy the files to current folder.

What is the result? "cp ../source/*" was expanded as "cp ../source/a ../source/b", so the ~/source/b file is replaced by a copy of a file, and there is no way to recover it any more!

If there were more than 2 files in that folder, the result would be different. For example, there were 3 files "a", "b", and "c". Then the "cp ../source/#" would have been expanded as "cp ../source/a ../source/b ../source/c", and the terminal would complaint:

cp: target `../source/c' is not a directory

At least there is some warnings, and the user will go back to check the command syntax. And there is no file being replaced (destroyed forever).

What if there is a folder in the source, and it is the "last" one? So far when I "ls", the name is sorted on alphabetic order, I guess the "cp" is using the same ordering to expand the "*" wild character. So let me create a folder "z" in the ~/source and execute the same command again:

~/target$ cp ../source/*

As expected, the terminal didn't complain anything, means the operation was successfully executed. The result is that all the files in the ../source/ are copied into ../source/z folder. Not exactly what I want.

So the feature of expanding the wild characters is dangerous when user input wrong parameters. It either: complain, copy files to unwanted place, or worse, replace an existing file unintentionally.

Suggestion: Change "cp" to complain if the user only input ONE parameter, before expanding the wild characters.

PS: After several minutes, I created a shell script thinking to replace the original /bin/cp:

if [ "$#" -eq 1 ]; then
echo "Usage: $0 at least 2 parameters" >&2
exit 1
echo $#
/bin/cp.origin $@
But no, it is not working. The shell expanded the wildcard character before it comes to the program. So there is no way to perform the task under such shell environment.