mv: Move o arquivo somente se o destino não existir

32

Posso usar mv file1 file2 de uma forma que mova apenas file1 para file2 se file2 não existir?

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 de -i ele também não me dá códigos de erro (sempre 141 em vez de 0 se movido e outra coisa se não for movido )

    
por Fabian Schmitthenner 10.12.2015 / 13:55

5 respostas

44

mv -vn file1 file2 . Este comando fará o que você quiser. Você pode pular -v se quiser.

-v torna verbose - mv dirá a você que ele moveu o arquivo se ele foi movido (útil, já que existe a possibilidade de o arquivo não ser movido)

-n é movido apenas se o arquivo2 não existir.

Por favor note, no entanto, que isto não é POSIX como sentado por ThomasDickey .

    
por 10.12.2015 / 14:06
15

mv -n

De man mv em um sistema GNU:

-n, --no-clobber
do not overwrite an existing file

Em um sistema FreeBSD:

-n Do not overwrite an existing file. (The -n option overrides any previous -f or -i options.)

    
por 10.12.2015 / 14:07
7
if [ ! -e file2 ] && [ ! -L file2 ]
then
    mv file1 file2
# else echo >&2 there is already a file2 file.
fi

Ou:

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

Só executaria mv se file2 não existir. Observe que não garante que file2 não seja substituído porque um file2 poderia ter sido criado entre o teste e o mv , mas observe que pelo menos as versões atuais do GNU mv com -i ou -n também não dão essa garantia (embora a condição de corrida seja mais restrita lá, já que a verificação é feita dentro de mv ).

Por outro lado, é portátil, permite discriminar entre os casos e funciona independentemente do tipo do arquivo file2 (regular, pipe, mesmo diretório ).

    
por 10.12.2015 / 14:00
4

Uma abordagem sem raça com o GNU ln fornecido file1 não é do tipo diretório :

ln -PT file1 file2 && rm file1

(Exceto para erros em alguns sistemas de arquivos de rede), isso garante que nenhum arquivo file2 será substituído (ou que se file2 for do tipo diretório, file1 não será movido para ele), porque o A chamada do sistema link() , ao contrário da chamada do sistema rename() , falhará se o destino existir.

No entanto, haverá um estado intermediário em que o arquivo existe como file1 e file2 .

A opção -T (para sempre fazer um link("file1", "file2") mesmo se file2 for do tipo diretório) é específica do GNU.

Você também pode usar o comando link :

link file1 file2 && rm file1

No entanto, se file1 for um symlink, 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 ) .

    
por 11.12.2015 / 12:45
0

Você também pode usar test -e name , que retornará verdadeiro se o nome existir (independentemente do arquivo, diretório ou link simbólico).

Por exemplo:

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...
    
por 11.12.2015 / 10:53

Tags