Czy mogę używać mv file1 file2
w taki sposób, że porusza się tylko file1
na file2
razie file2
nie istnieje?
próbowałem
yes n | mv -i file1 file2
(pozwala to mv
zapytać, czy plik2 powinien zostać zastąpiony i automatycznie odpowiedzieć nie), ale oprócz nadużywania -i
nie daje mi również ładnych kodów błędów (zawsze 141 zamiast 0, jeśli przeniesiono i coś innego, jeśli nie przeniesiono)
pipefail
włączoną opcję, ponieważ 141 oznacza status wyjściayes
, a niemv
który nie miałby powodu, aby uzyskać SIGPIPE tutaj.-T
takiego.mv
zamiast statusuyes
, najprostszym rozwiązaniem może byćmv -i file1 file2 < <(yes n)
Odpowiedzi:
mv -vn file1 file2
. To polecenie zrobi, co chcesz. Możesz pominąć,-v
jeśli chcesz.-v
sprawia, że jest pełny - mv powie ci, że przeniósł plik, jeśli go przeniesie (przydatne, ponieważ istnieje możliwość, że plik nie zostanie przeniesiony)-n
przesuwa się tylko wtedy, gdy plik2 nie istnieje.Pamiętaj jednak, że nie jest to POSIX, jak wspomniał ThomasDickey .
źródło
strace
pokazuje, że używa (w moim systemie): stat ("plik2", 0x7ffe3e705d10) = -1 ENOENT (Brak takiego pliku lub katalogu) lstat ("plik1", {st_mode = S_IFREG | 0644, st_size = 0, ...}) = 0 lstat („file2”, 0x7ffe3e705a10) = -1 ENOENT (Brak takiego pliku lub katalogu) zmiana nazwy („file1”, „file2”) = 0 lseek (0, 0, SEEK_CUR) = -1 ESPIPE (nielegalne poszukiwanie). Wygląda na to, że zmieniono nazwę. @ Rozwiązanie StéphaneChazelas wydaje się być odpowiednie, jeśli naprawdę chcesz zrobić to bez wyścigu.renameat2
mv -n
Z
man mv
systemu GNU:W systemie FreeBSD:
źródło
Lub:
Działa tylko,
mv
jeślifile2
nie istnieje. Zauważ, że nie gwarantuje to, że afile2
nie zostanie zastąpione, ponieważfile2
można było utworzyć między testem a testemmv
, ale zauważ, że przynajmniej obecne wersje GNUmv
z taką gwarancją-i
lub-n
nie dają takiej gwarancji (chociaż warunki wyścigu są węższe tam, ponieważ kontrola odbywa się w ciągumv
).Z drugiej strony jest przenośny, pozwala rozróżniać przypadki i działa niezależnie od typu
file2
pliku (zwykły, potokowy, a nawet katalog ).źródło
renameat2
co możesz daćRENAME_NOREPLACE
flagę. Wierzę, że to atomowo sprawdza istnienie pliku, a następnie przenosi plik.Podejście bez wyścigu z
ln
udostępnionym GNUfile1
nie jest katalogiem typu :(Z wyjątkiem błędów w niektórych sieciowych systemach plików), co gwarantuje, że żaden
file2
plik nie zostanie przesłonięty (lub, że jeślifile2
katalog typufile1
jest nie przeniesiony do niego), ponieważlink()
wywołanie systemowe, w przeciwieństwie dorename()
wywołania systemowego, zakończy się niepowodzeniem, jeśli cel istnieje.Będzie jednak stan pośredni, w którym plik istnieje zarówno jako, jak
file1
ifile2
.-T
Opcja (zawsze zrobićlink("file1", "file2")
, nawet jeślifile2
jest z katalogu typu) jest specyficzne dla GNU.Możesz także użyć
link
polecenia:Jeśli jednak
file1
jest dowiązaniem symbolicznym, w zależności od implementacjifile2
będzie dowiązaniem twardym do tego dowiązania symbolicznego lub do celu tego dowiązania symbolicznego (w Solarisie, użyj/usr/sbin/link
, nie/usr/xpg4/bin/link
).źródło
renameat2
z flagąRENAME_NOREPLACE
jest atomowy?Możesz także użyć parametru,
test -e name
który zwróci true, jeśli nazwa istnieje (niezależnie od pliku, katalogu lub dowiązania symbolicznego).Na przykład:
źródło
ln -s doesnotexist exists; test -e exists || echo "does it really not exist?"
… To samo na przykładln -s /var/spool/cron/crontabs/. exists
(i nie jesteś rootem ani członkiem grupy crontab).