117

I'm using Mac OS X. I'm trying to copying some files with cp command for a build script like this.

cp ./src/*/*.h ./aaa 

But this command fires an error if there is no .h file in ./src directory. How to make the command don't fire the error? (silent failure) The error makes build result fail, but I just want to copy when only there are some header file.

6 Answers 6

141

If you're talking about the error message, you can suppress that by sending it to the bit bucket:

cp ./src/*/*.h ./aaa 2>/dev/null 

If you want to suppress the exit code and the error message:

cp ./src/*/*.h ./aaa 2>/dev/null || : 
13
  • 21
    It would be nice to explain what : means in this context. Commented Feb 10, 2014 at 15:35
  • 37
    @PiotrDobrogost: In Bash and some other shells the colon is a null utility (no-op). It's specified by POSIX. Since it always returns true, it's used here to suppress the exit code of a failed cp (should that be desired). The shell builtin true could be used instead and would be more readable. Commented Feb 10, 2014 at 15:46
  • 1
    More about :What Is the Purpose of the `:' (colon) GNU Bash Builtin? Commented Feb 10, 2014 at 15:49
  • 5
    This will also ignore other errors (source/destination directory doesn't exist, source file exists but is not readable, disk full, read-only filesystem, IO error, cp not being in PATH somehow...) Commented Oct 24, 2018 at 19:32
  • syntax error near unexpected token `||' Commented Jul 24, 2019 at 20:53
27

You're looking for something along the lines of

if [ -e file ] then cp file /somewhere fi 

(Unfortunately, the -f option is not the droid you're looking for.)

If you want to match a glob, that won't work; use find instead, e.g.:

find ./src -name \*.h -exec cp {} ./destination \; 
2
  • 2
    Note that there is a potential TOCTOU issue with such an approach (e.g. if you use set -e, and the file disappears between the [ and the cp invocations, your script will crash). Commented Oct 24, 2018 at 19:34
  • You could explain why use -e instead of -f and what is the difference. Commented Jan 6, 2024 at 19:31
17

Piping the result to true ensures that the command will always succeed. I have tried this on Linux but not on any Mac OS:

cp ./src/*/*.h ./aaa | true 
4
  • 13
    The simple pipe | is always run while || is only done in case of an error. And true is usually a binary while the colon : is a builtin and doesn't consume a PID. Commented Feb 6, 2015 at 18:16
  • 1
    A bash script on MacOS - Yosemite containing "cp ./src/*/*.h ./aaa" command does not error out if the .h files do not exist. Commented Feb 21, 2015 at 7:29
  • Simple, readable, and working. This is exactly what I needed, thanks mate. Commented Jul 8, 2022 at 23:36
  • @Vivek not actually - in a script this behavior depends on flags. I would not count on default flags values. || true would always work, OTOH. Commented May 10, 2024 at 17:48
13

Old question, but might still be relevant for others.
If you don't need to use cp, you could try with rsync.
To copy all files from a source to a destination directory, run:

rsync -avzh --ignore-errors /path/to/source /path/to/destination 

Rsync comes with most Unix-like systems such as Linux, Mac OS X or FreeBSD.

3
  • 5
    You could use rsync instead of cp, adding the parameter --ignore-missing-args: rsync -av --ignore-missing-args ./src/*/*.h ./aaa This has the advantage over --ignore-errors that the only errors ignored are those related to source files not existing. With --ignore-errors every error is ignored, which may be dangerous. Also, take into account that this parameter is fairly recent, so it might not be present in old versions of rsync. Commented Oct 15, 2015 at 10:18
  • what if the source directory doesn't exist? Commented Jun 18, 2020 at 7:37
  • 1
    I don't think that should be the responsibility of rsync to be honest. Rather, you can check upfront if the source directory exists, e.g. [ -d /path/to/source ] && rsync -avzh --ignore-errors /path/to/source /path/to/destination Commented Jun 18, 2020 at 11:30
2

You could force the correct error status. With a function:

$ cpalways () { cp $1 $2 2>/dev/null ; return 0 ; } 

Given the following:

$ ls foo bar baz ls: baz: No such file or directory bar foo 

Regular copy will return an error. It will return an exit status of 1.

$ cp baz bar ; echo $? cp: baz: No such file or directory 1 

If we use the cpalways() function above, any errors will be hidden:

$ cpalways baz bar ; echo $? 0 $ cpalways foo bar ; echo $? 0 $ cpalways baz bar ; echo $? 0 
-1

This works

$(cp ./src/*/*.h ./aaa | true)

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.