如果 bash 脚本中不存在则原子创建文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13828544/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 04:00:24  来源:igfitidea点击:

atomic create file if not exists from bash script

clinuxbash

提问by Jimm

In system call open(), if I open with O_CREAT | O_EXCL, the system call ensures that the file will only be created if it does not exist. The atomicity is guaranteed by the system call. Is there a similar way to create a file in an atomic fashion from a bash script?

在系统调用中open(),如果我用 来打开O_CREAT | O_EXCL,系统调用确保文件只有在它不存在时才会被创建。原子性由系统调用保证。有没有类似的方法可以从 bash 脚本以原子方式创建文件?

UPDATE: I found two different atomic ways

更新:我发现了两种不同的原子方式

  1. Use set -o noclobber. Then you can use > operator atomically.
  2. Just use mkdir. Mkdir is atomic
  1. 使用 set -o noclobber。然后您可以原子地使用 > 运算符。
  2. 只需使用 mkdir。Mkdir 是原子的

回答by gniourf_gniourf

A 100% pure bash solution:

100% 纯 bash 解决方案:

set -o noclobber
{ > file ; } &> /dev/null

This command creates a file named fileif there's no existent file named file. If there's a file named file, then do nothing (but return a non-zero return code).

此命令创建一个名为file如果有一个名为没有存在的文件file。如果有一个名为 的文件file,则什么都不做(但返回一个非零的返回码)。

Pros wrt the touchcommand:

优点是touch命令:

  • Doesn't update timestamp if file already existed
  • 100% bash builtin
  • Return code as expected: fail if filealready existed or if filecouldn't be created; success if filedidn't exist and was created.
  • 如果文件已存在,则不更新时间戳
  • 100% bash 内置
  • 按预期返回代码:如果file已经存在或file无法创建则失败;如果file不存在并被创建,则成功。

Cons:

缺点:

  • need to set the noclobberoption (but it's okay in a script, if you're careful with redirections, or unset it afterwards).
  • 需要设置noclobber选项(但在脚本中没问题,如果你小心重定向,或者之后取消设置)。

I guess this solution is really the bash counterpart of the opensystem call with O_CREAT | O_EXCL.

我猜这个解决方案真的是open系统调用的 bash 对应物O_CREAT | O_EXCL.

回答by thejoshwolfe

Here's a bash function using the mv -ntrick:

这是一个使用mv -n技巧的 bash 函数:

function mkatomic() {
  f="$(mktemp)"
  mv -n "$f" ""
  if [ -e "$f" ]; then
    rm "$f"
    echo "ERROR: file exists:" "" >&2
    return 1
  fi
}

Examples:

例子:

$ mkatomic foo
$ wc -c foo
0 foo
$ mkatomic foo
ERROR: file exists: foo

回答by twalberg

Just to be clear, ensuring the file will only be created if it doesn't exist is not the same thing as atomicity. The operation is atomic if and only if, when two or more separate threads attempt to do the same thing at the same time, exactly one will succeed and all others will fail.

需要明确的是,确保仅在文件不存在时才创建文件与原子性不同。该操作是原子的,当且仅当两个或多个单独的线程尝试同时执行相同的操作时,只有一个线程会成功,而所有其他线程都会失败。

The best way I know of to create a file atomically in a shell script follows this pattern (and it's not perfect):

我所知道的在 shell 脚本中以原子方式创建文件的最佳方法遵循这种模式(它并不完美):

  1. create a file that has an extremely high chance of not existing (using a decent random number selection or something in the file name), and place some unique content in it (something that no other thread would have - again, a random number or something)
  2. verify that the file exists and contains the contents you expect it to
  3. create a hard link from that file to the desired file
  4. verify that the desired file contains the expected contents
  1. 创建一个极有可能不存在的文件(使用合适的随机数选择或文件名中的某些内容),并在其中放置一些独特的内容(其他线程不会拥有的内容 - 再次,随机数或其他内容) )
  2. 验证文件是否存在并包含您期望的内容
  3. 创建从该文件到所需文件的硬链接
  4. 验证所需文件是否包含预期内容

In particular, touchis not atomic, since it will create the file if it's not there, or simply update the timestamp. You might be able to play games with different timestamps, but reading and parsing a timestamp to see if you "won" the race is harder than the above. mkdircan be atomic, but you would have to check the return code, because otherwise, you can only tell that "yes, the directory was created, but I don't know which thread won". If you're on a file system that doesn't support hard links, you might have to settle for a less ideal solution.

特别是,touch它不是原子的,因为如果文件不存在,它将创建文件,或者只是更新时间戳。您也许可以玩具有不同时间戳的游戏,但是读取和解析时间戳以查看您是否“赢得”了比赛比上述更难。mkdir可以是原子的,但您必须检查返回码,否则,您只能说“是的,目录已创建,但我不知道哪个线程获胜”。如果您使用的文件系统不支持硬链接,您可能不得不接受一个不太理想的解决方案。

回答by Don Branson

You could create it under a randomly-generated name, then rename (mv -n random desired) it into place with the desired name. The rename will fail if the file already exists.

您可以使用随机生成的名称创建它,然后将mv -n random desired它重命名 ( ) 到所需名称的位置。如果文件已经存在,重命名将失败。

Like this:

像这样:

#!/bin/bash

touch randomFileName
mv -n randomFileName lockFile

if [ -e randomFileName ] ; then
    echo "Failed to acquired lock"
else
    echo "Acquired lock"
fi

回答by Kylo

touchis the command you are looking for. It updates timestamps of the provided file if the file exists or creates it if it doesn't.

touch是您要查找的命令。如果文件存在,它会更新所提供文件的时间戳,如果文件不存在则创建它。