113

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

140

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
  • 20
    It would be nice to explain what : means in this context. 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. Feb 10, 2014 at 15:46
  • 1
  • 4
    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...) Oct 24, 2018 at 19:32
  • syntax error near unexpected token `||'
    – thang
    Jul 24, 2019 at 20:53
25

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
  • 1
    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). Oct 24, 2018 at 19:34
  • You could explain why use -e instead of -f and what is the difference. Jan 6 at 19:31
16

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
3
  • 12
    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.
    – ott--
    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.
    – Vivek
    Feb 21, 2015 at 7:29
  • Simple, readable, and working. This is exactly what I needed, thanks mate. Jul 8, 2022 at 23:36
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.
    – jesjimher
    Oct 15, 2015 at 10:18
  • what if the source directory doesn't exist?
    – Arrrow
    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
    – mre
    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.

Not the answer you're looking for? Browse other questions tagged .