Posso usar mv file1 file2
de uma forma que só se move file1
para file2
se file2
não existe?
eu tentei
yes n | mv -i file1 file2
(isso permite mv
perguntar se o arquivo2 deve ser substituído e responder automaticamente não), mas além de abusar -i
, também não me fornece códigos de erro agradáveis (sempre 141 em vez de 0 se movido e outra coisa se não for movido)
pipefail
opção como 141, que seria o status de saídayes
, e nãomv
teria razão para obter um SIGPIPE aqui.-T
para isso.mv
e não a deyes
, a solução mais simples poderia sermv -i file1 file2 < <(yes n)
Respostas:
mv -vn file1 file2
. Este comando fará o que você deseja. Você pode pular-v
se quiser.-v
torna detalhado - o mv dirá que ele moveu o arquivo se o mover (útil, pois existe a possibilidade de o arquivo não ser movido)-n
move somente se o arquivo2 não existir.Observe, no entanto, que isso não é POSIX, como mencionado por ThomasDickey .
fonte
strace
mostra que ele usa (no meu sistema): stat ("arquivo2", 0x7ffe3e705d10) = -1 ENOENT (nenhum arquivo ou diretório desse tipo) lstat ("arquivo1", {st_mode = S_IFREG | 0644, st_size = 0, ...}) = 0 lstat ("arquivo2", 0x7ffe3e705a10) = -1 ENOENT (não existe esse arquivo ou diretório) renomear ("arquivo1", "arquivo2") = 0 lseek (0, 0, SEEK_CUR) = -1 ESPIPE (busca ilegal). Portanto, renomear parece ser usado. A solução @ StéphaneChazelas parece ser a correta, se você realmente quiser fazê-lo sem correr.renameat2
mv -n
A partir
man mv
de um sistema GNU:Em um sistema FreeBSD:
fonte
Ou:
Seria executado apenas
mv
sefile2
não existir. Observe que não garante que afile2
não seja substituída porque afile2
poderia ter sido criada entre o teste e amv
, mas observe que pelo menos as versões atuais do GNUmv
com-i
ou-n
não oferecem essa garantia (embora a condição de corrida seja mais estreita desde que a verificação seja feita dentromv
).Na outra ponta, ele é portátil, permite discriminar entre os casos, e funciona independentemente do tipo do
file2
arquivo (regular, tubulação, mesmo diretório ).fonte
renameat2
umaRENAME_NOREPLACE
bandeira. Eu acredito que isso verifica atomicamente a existência do arquivo e depois move o arquivo.Uma abordagem sem corrida com o GNU
ln
fornecidofile1
não é do tipo diretório :(Exceto para erros em alguns sistemas de arquivos de rede), que garante que nenhum
file2
arquivo será substituído (ou que, sefile2
for do tipo diretório,file1
não será movido para ele), porque alink()
chamada do sistema, ao contrário darename()
chamada do sistema, falhará se o existe o alvo.No entanto, haverá um estado intermediário em que o arquivo existe como
file1
efile2
.A
-T
opção (para fazer sempre um diretóriolink("file1", "file2")
mesmo quefile2
seja do tipo) é específica do GNU.Você também pode usar o
link
comando:No entanto, se
file1
houver um link simbólico, dependendo da implementação,file2
será um link físico para esse link simbólico ou para o destino desse link simbólico (no Solaris, use/usr/sbin/link
, não/usr/xpg4/bin/link
).fonte
renameat2
com flagRENAME_NOREPLACE
é atômico?Você também pode usar o
test -e name
que retornará true se o nome existir (independentemente do arquivo, diretório ou link simbólico).Por exemplo:
fonte
ln -s doesnotexist exists; test -e exists || echo "does it really not exist?"
. O mesmo acontece com, por exemploln -s /var/spool/cron/crontabs/. exists
(e você não é root ou membro do grupo crontab).