Как позволить команде cp не выдавать ошибку, если исходный файл не существует?

59

Я использую Mac OS X. Я пытаюсь скопировать некоторые файлы с помощью команды cp для сценария сборки, подобного этому.

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

Но эта команда выдает ошибку, если в каталоге ./src нет файла .h. Как заставить команду не выдавать ошибку? (тихий сбой) Ошибка приводит к сбою результата сборки, но я просто хочу скопировать, когда есть только заголовочный файл.

Eonil
источник

Ответы:

69

Если вы говорите о сообщении об ошибке, вы можете подавить его, отправив его в область битов:

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

Если вы хотите подавить код выхода и сообщение об ошибке:

cp ./src/*/*.h ./aaa 2>/dev/null || :
Деннис Уильямсон
источник
8
Было бы неплохо объяснить, что :значит в этом контексте.
Петр Доброгост
23
@PiotrDobrogost: В Bash и некоторых других оболочках двоеточие является нулевой утилитой (no-op). Это указано в POSIX . Поскольку он всегда возвращает true, он используется здесь для подавления кода выхода из-за сбоя cp(если это желательно). trueВместо этого можно использовать встроенную оболочку, которая будет более читабельной.
Деннис Уильямсон
Подробнее о :- Какова цель `: '(двоеточие) GNU Bash Builtin?
Петр Доброгост
1
Это также будет игнорировать другие ошибки (исходный / целевой каталог не существует, исходный файл существует, но недоступен для чтения, диск заполнен, файловая система только для чтения, ошибка ввода-вывода, cpотсутствует PATHкаким-либо образом ...)
Владимир Пантелеев
синтаксическая ошибка рядом с неожиданным токеном `|| '
Тханг
13

Вы ищете что-то вроде

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

(К сожалению, -fопция не та, которую вы ищете.)

Если вы хотите сопоставить глобус, это не сработает; использовать findвместо этого, например:

find ./src -name \*.h -exec cp {} ./destination \;
Брэд Акерман
источник
Обратите внимание, что при таком подходе существует потенциальная проблема TOCTOU (например, если вы используете set -eфайл, и файл исчезает между вызовами [и cp, ваш сценарий будет аварийно завершаться).
Владимир Пантелеев,
9

Старый вопрос, но все еще может быть актуальным для других.
Если вам не нужно использовать cp, вы можете попробовать использовать rsync.
Чтобы скопировать все файлы из исходного каталога в каталог назначения, запустите:

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

Rsync поставляется с большинством Unix-подобных систем, таких как Linux, Mac OS X или FreeBSD.

MRE
источник
4
Вы можете использовать rsync вместо cp, добавив параметр --ignore-missing-args: rsync -av --ignore-missing-args ./src/*/*.h ./aaaЭто дает преимущество в --ignore-errorsтом, что игнорируются только ошибки, связанные с несуществующими исходными файлами. При этом --ignore-errorsкаждая ошибка игнорируется, что может быть опасно. Также примите во внимание, что этот параметр довольно недавний, поэтому он может отсутствовать в старых версиях rsync.
jesjimher
6

Передача результата в true гарантирует, что команда всегда будет успешной. Я пробовал это на Linux, но не на любой Mac OS:

cp ./src/*/*.h ./aaa | true
Вивек
источник
5
Простая труба |всегда запускается, а ||выполняется только в случае ошибки. И true, как правило, в то время как бинарное двоеточие :является встроенной и не потребляет PID.
ot--
Скрипт bash на MacOS - Yosemite, содержащий команду «cp ./src/*/*.h ./aaa», не выдает ошибку, если файлы .h не существуют.
Вивек
2

Вы можете вызвать правильный статус ошибки. С функцией:

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

Учитывая следующее:

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

Обычная копия вернет ошибку. Будет возвращено состояние выхода 1.

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

Если мы используем функцию cpalways () выше, любые ошибки будут скрыты:

$ cpalways baz bar ; echo $?
0
$ cpalways foo bar ; echo $?
0
$ cpalways baz bar ; echo $?
0
Стефан Ласевский
источник