mv: Yalnızca hedef yoksa dosyayı taşı


44

Ben kullanabilir miyim mv file1 file2sadece hareket bir şekilde file1karşı file2eğer file2yok?

denedim

yes n | mv -i file1 file2

(bu mv, file2 dosyasının geçersiz kılınması gerekip gerekmediğini otomatik olarak cevaplaması gerekip gerekmediğini sormasını sağlar ) ancak suistimal etmenin yanı sıra -ibana güzel hata kodları da vermez (taşınırsa her zaman 0 yerine 141 ve taşınırsa başka bir şey)


3
Olması gerekir pipefail141 çıkış Statüsü ne kadar seçeneği yesdeğil, mvburada bir SIGPIPE almak için hiçbir sebep olurdu.
Stéphane Chazelas,

Bu yaklaşım ayrıca eğer file2 bir dizin ise başarısız olur (bu da file1'i file2 dizinine taşır). GNU mv bunun -Tiçin var.
Stéphane Chazelas,

@ StéphaneChazelas Eğer arzu, mvbunun yerine çıkış durumunu kullanmaksa yes, en basit çözüm olabilirmv -i file1 file2 < <(yes n)
kasperd

Yanıtlar:


63

mv -vn file1 file2. Bu komut ne istersen onu yapacak. İstersen atlayabilirsin -v.

-v ayrıntılı hale getirir - mv, taşıdığında dosyayı taşıdığını söyler (yararlı, çünkü dosyanın taşınmaması olasılığı vardır)

-n sadece file2 mevcut değilse hareket eder.

Ancak, bunun ThomasDickey tarafından belirtildiği gibi POSIX olmadığını unutmayın .


2
Ancak, POSIX değil .
Thomas Dickey,

1
@ThomasDickey POSIX bunu atomik bir şekilde destekliyor mu?
Fabian Schmitthenner

3
to @Fabian: Muhtemelen hayır, ancak önerilen cevaplarda bile, nasıl yazıldığına bağlı olarak araçlar içinde bir yarış olasılığı vardır.
Thomas Dickey,

3
bu straceyarışsız görünmüyor, kullandığını gösteriyor (sistemimde): stat ("file2", 0x7ffe3e705d10) = -1 ENOENT (Böyle bir dosya veya dizin yok) lstat ("file1", {st_mode = S_IFREG | 0644, st_size = 0, ...}) = 0 lstat ("dosya2", 0x7ffe3e705a10) = -1 ENOENT (Böyle bir dosya veya dizin yok) yeniden adlandırın ("dosya1", "dosya2") = 0 lseek (0, 0, SEEK_CUR) = -1 ESPIPE (Geçersiz arama). Yani yeniden adlandırmak kullanılmış gibi görünüyor. @ StéphaneChazelas çözümü gerçekten özgürce yarışmak istiyorsanız doğru çözüm gibi görünüyor.
Fabian Schmitthenner

2
Neden kullanılmadığını merak ediyorumrenameat2
Fabian Schmitthenner

16

mv -n

Gönderen man mvbir GNU sistemi üzerinde:

-n, --no-clobber
varolan bir dosyanın üzerine yazmaz

FreeBSD sisteminde:

-nMevcut bir dosyanın üzerine yazmayın. (-N seçeneği, önceki -f veya -i seçeneklerini geçersiz kılar.)


10
if [ ! -e file2 ] && [ ! -L file2 ]
then
    mv file1 file2
# else echo >&2 there is already a file2 file.
fi

Veya:

if ! ls -d file2 > /dev/null 2>&1
then
    mv file1 file2
fi

Sadece mvyoksa çalıştırabilirdim file2. Bir garanti etmediğini Not file2bir nedeni geçersiz kılınan olmayacak file2testi ve aralarında oluşturulmuş olabilir mvGNU azından mevcut sürümleri o, ancak not mvile -iveya -nyarış durumu daha dar olmasına rağmen bu garantiyi ya (vermeyin Orada kontrol yapıldıktan sonra mv.

Diğer ucunda, taşınabilir, davalar arasında ayrım yapmanızı sağlar ve file2dosyanın türünden bağımsız olarak çalışır (normal, pipe, hatta dizin ).


3
Bu, varlık kontrolü ile hareket arasında bir dosyanın yazılabileceği bir yarış şartı yaratır mı?
Fabian Schmitthenner

3
Ne yaparsan yap, daima bir olasılık.
Majenko,

3
Linux API renameat2size RENAME_NOREPLACEbayrak verebilir . Bunun atomik olarak dosyanın varlığını kontrol ettiğine ve sonra dosyayı taşıdığına inanıyorum.
Fabian Schmitthenner

dizinler için -d, veya bağlantılar için -l veya hatta herhangi bir dosya türü için -e
Majenko

Yeniden adlandırmak yarışsız olabilir ancak mv komutunun geri kalanı değildir. Bağlantının kaldırılması gerekmediğini düşünüyorsa, aniden yeniden adlandırma işlemi başarısız olur (hata olur) hatası verir.
Majenko

8

lnSağlanan GNU ile yarışsız bir yaklaşım file1, tür dizininde değildir :

ln -PT file1 file2 && rm file1

(Bazı ağ dosya sistemlerindeki hatalar hariç), hiçbir file2dosyanın geçersiz kılmayacağını garanti eder (ya da bu file2tür bir dizin ise , bu dosyaya file1taşınmaz), çünkü link()sistem çağrısı, sistem çağrısı aksine, rename()sistem çağrısı başarısız olur. Hedef var.

Ancak, dosyanın hem file1ve hem de olduğu bir ara durum olacaktır file2.

Bu -Tseçenek (her zaman bir dizin dizini link("file1", "file2")olsa bile yapmak için) seçeneği file2GNU'ya özgüdür.

linkKomutu da kullanabilirsiniz :

link file1 file2 && rm file1

Ancak, file1uygulamaya bağlı olarak, bir bağlantı ise , file2bu bağlantıya veya bu bağlantı bağlantısının hedefine bir sabit bağlantı olacaktır (Solaris'te, kullanmayın /usr/sbin/link, kullanılmamalıdır /usr/xpg4/bin/link).


2
renameat2Bayraklı linux apinin RENAME_NOREPLACEatomik olup olmadığını biliyor musunuz ?
Fabian Schmitthenner

1
@Fabian, AFAICT bunun için amaçlandı ama çok yeni ve tüm dosya sistemlerinde desteklenmiyor. İleride, Linux'ta gelecekteki mv uygulamalarının bunu kullanmasını bekleyebiliriz. Bunun için tasarlandı.
Stéphane Chazelas

0

Ayrıca test -e name, ad varsa (hangisi dosya, dizin ya da sembolik bağlantıya bakılmaksızın) true değerini döndürür kullanabilirsiniz .

Örneğin:

touch file
mkdir dir
ln -s file symlink
test -e file && echo file exists
test -e dir && echo dir exists
test -e symlink && echo symlink exists
test -e file || echo you wont see this echo
test -e doesnotexist || echo doesnotexist does not exist...

1
Ama ln -s doesnotexist exists; test -e exists || echo "does it really not exist?". Örneğin aynı ln -s /var/spool/cron/crontabs/. exists(ve siz kök veya crontab grubunun üyesi değilsiniz).
Stéphane Chazelas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.