Jak pozwolić komendzie „cp” nie uruchamiać błędu, gdy plik źródłowy nie istnieje?

59

Korzystam z systemu Mac OS X. Próbuję skopiować niektóre pliki za pomocą polecenia cp dla takiego skryptu kompilacji.

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

Ale to polecenie uruchamia błąd, jeśli nie ma pliku .h w katalogu ./src. Jak sprawić, by polecenie nie uruchamiało błędu? (cicha awaria) Błąd powoduje niepowodzenie kompilacji, ale chcę tylko skopiować, gdy jest tylko jakiś plik nagłówkowy.

Eonil
źródło

Odpowiedzi:

69

Jeśli mówisz o komunikacie o błędzie, możesz go ukryć, wysyłając go do segmentu bitów:

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

Jeśli chcesz ukryć kod wyjścia i komunikat o błędzie:

cp ./src/*/*.h ./aaa 2>/dev/null || :
Dennis Williamson
źródło
8
Dobrze byłoby wyjaśnić, co :oznacza w tym kontekście.
Piotr Dobrogost
23
@PiotrDobrogost: W Bash i niektórych innych powłokach dwukropek jest narzędziem zerowym (no-op). Jest to określone przez POSIX . Ponieważ zawsze zwraca wartość true, służy tutaj do tłumienia kodu wyjścia nieudanego cp(jeśli jest to pożądane). trueZamiast tego można użyć wbudowanej powłoki i będzie ona bardziej czytelna.
Dennis Williamson
Więcej informacji na temat :- Jaki jest cel wbudowanego GNU Bash `: '(dwukropek)?
Piotr Dobrogost
1
Zignoruje to także inne błędy (katalog źródłowy / docelowy nie istnieje, plik źródłowy istnieje, ale nie można go odczytać, dysk jest pełny, system plików tylko do odczytu, błąd we / wy, cpnie jest w PATHjakiś sposób ...)
Vladimir Panteleev
błąd składni w pobliżu nieoczekiwanego tokena `|| '
Thang
13

Szukasz czegoś w stylu

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

(Niestety -fnie jest to droid, którego szukasz).

Jeśli chcesz dopasować glob, to nie zadziała; findzamiast tego użyj np .:

find ./src -name \*.h -exec cp {} ./destination \;
Brad Ackerman
źródło
Należy pamiętać, że istnieje potencjalny problem TOCTOU z takiego podejścia (np jeśli używasz set -e, a plik znika między [a cpinwokacje, skrypt padnie).
Vladimir Panteleev
9

Stare pytanie, ale może być nadal istotne dla innych.
Jeśli nie potrzebujesz używać cp, możesz spróbować z rsync.
Aby skopiować wszystkie pliki ze źródła do katalogu docelowego, uruchom:

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

Rsync jest dostarczany z większością systemów uniksowych, takich jak Linux, Mac OS X lub FreeBSD.

mre
źródło
4
Możesz użyć rsync zamiast cp, dodając parametr --ignore-missing-args: rsync -av --ignore-missing-args ./src/*/*.h ./aaaMa to tę zaletę, --ignore-errorsże jedynymi ignorowanymi błędami są te związane z nieistniejącymi plikami źródłowymi. Z --ignore-errorskażdy błąd jest ignorowany, co może być niebezpieczne. Weź również pod uwagę, że ten parametr jest dość nowy, więc może nie być obecny w starych wersjach rsync.
jesjimher
6

Przesłanie wyniku do wartości true zapewnia, że ​​polecenie zawsze się powiedzie. Próbowałem tego na Linuksie, ale nie na żadnym Mac OS:

cp ./src/*/*.h ./aaa | true
Vivek
źródło
5
Prosta rura |jest zawsze uruchamiana, podczas gdy ||jest wykonywana tylko w przypadku błędu. I truejest zwykle dwójkowy, podczas gdy dwukropek :jest wbudowany i nie zużywa PID.
ott--
Skrypt bash na MacOS - Yosemite zawierający polecenie „cp ./src/*/*.h ./aaa” nie powoduje błędu, jeśli pliki .h nie istnieją.
Vivek
2

Możesz wymusić poprawny status błędu. Z funkcją:

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

Biorąc pod uwagę następujące kwestie:

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

Zwykła kopia zwróci błąd. Zwróci status wyjścia 1.

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

Jeśli użyjemy powyższej funkcji cpalways (), wszelkie błędy zostaną ukryte:

$ cpalways baz bar ; echo $?
0
$ cpalways foo bar ; echo $?
0
$ cpalways baz bar ; echo $?
0
Stefan Lasiewski
źródło