Могу ли я использовать mv file1 file2
таким образом , что она движется только file1
в file2
случае file2
не существует?
я пробовал
yes n | mv -i file1 file2
(это позволяет mv
спросить, должен ли файл2 быть переопределен и автоматически ответить «нет»), но кроме злоупотребления -i
он также не дает мне хороших кодов ошибок (всегда 141 вместо 0, если перемещено, и что-то еще, если не перемещено)
pipefail
опция, так как 141 будет статусом выходаyes
, но это неmv
будет иметь никаких причин для получения SIGPIPE здесь.-T
для этого.mv
а не статусyes
, самое простое решение может бытьmv -i file1 file2 < <(yes n)
Ответы:
mv -vn file1 file2
, Эта команда будет делать то, что вы хотите. Вы можете пропустить,-v
если хотите.-v
делает его многословным - mv скажет вам, что он переместил файл, если переместит его (полезно, поскольку есть вероятность, что файл не будет перемещен)-n
перемещается, только если file2 не существует.Обратите внимание, однако, что это не POSIX, как упомянуто ThomasDickey .
источник
strace
показывает, что он использует (в моей системе): stat ("file2", 0x7ffe3e705d10) = -1 ENOENT (нет такого файла или каталога) lstat ("file1", {st_mode = S_IFREG | 0644, st_size = 0, ...}) = 0 lstat ("file2", 0x7ffe3e705a10) = -1 ENOENT (такой файл или каталог отсутствует) rename ("file1", "file2") = 0 lseek (0, 0, SEEK_CUR) = -1 ESPIPE (Незаконный поиск). Таким образом, переименование, кажется, используется. Решение @ StéphaneChazelas кажется правильным, если вы действительно хотите сделать его бесплатным.renameat2
mv -n
В
man mv
системе GNU:В системе FreeBSD:
источник
Или:
Будет работать только
mv
еслиfile2
не существует. Обратите внимание, что это не гарантирует, что afile2
не будет переопределено, потомуfile2
что между тестом и функцией могло быть создано amv
, но учтите, что по крайней мере текущие версии GNUmv
с-i
или-n
не дают такую гарантию (хотя условие гонки более узкое) там, так как проверка делается в течениеmv
).С другой стороны, он переносим, позволяет различать случаи и работает независимо от типа
file2
файла (обычный, конвейерный, даже каталог ).источник
renameat2
который вы можете задатьRENAME_NOREPLACE
. Я считаю, что это атомарно проверяет существование файла, а затем перемещает файл.Подход без расы с
ln
предоставленной GNUfile1
не относится к каталогу типов :(За исключением ошибок в некоторых сетевых файловых системах), это гарантирует, что ни один
file2
файл не будет переопределен (или что, если онfile2
имеет тип каталога,file1
не будет перемещен в него), потому чтоlink()
системный вызов, в отличие отrename()
системного вызова, завершится неудачей, если цель существует.Однако будет промежуточное состояние, в котором файл существует как
file1
иfile2
.-T
Вариант (всегда делатьlink("file1", "file2")
даже еслиfile2
есть директории типа) является GNU-специфично.Вы также можете использовать
link
команду:Однако, если
file1
это символическая ссылка, в зависимости от реализации,file2
будет либо жесткая ссылка на эту символическую ссылку, либо на цель этой символической ссылки (в Solaris используйте/usr/sbin/link
, а не/usr/xpg4/bin/link
).источник
renameat2
с флагомRENAME_NOREPLACE
является атомным?Вы также можете использовать,
test -e name
который будет возвращать true, если имя существует (независимо от файла, каталога или символической ссылки).Например:
источник
ln -s doesnotexist exists; test -e exists || echo "does it really not exist?"
. То же самое, например,ln -s /var/spool/cron/crontabs/. exists
(и вы не являетесь пользователем root или членом группы crontab).