如何将输出重定向到文件,如果不存在则不创建文件?

时间:2018-12-29 01:04:39

标签: shell

我需要将输出重定向到外壳中带有>的文件,但是如果该文件不存在,则不应创建该文件。如何实现呢?

我尝试通过创建指向文件的符号链接并重定向到该符号链接来进行尝试,但是很遗憾,如果文件尚不存在,还是会创建该文件。

可能我需要重定向到执行检查的单独程序,而不是shell。有人知道一个程序可以做到这一点吗?

注意:我需要它在OpenWrt中运行(即,使用busybox的实用程序版本)。

5 个答案:

答案 0 :(得分:2)

您没有指定设备文件在什么时候不应该存在。如果您想问,在调用program时应检查设备文件的存在,则可以在Bash中使用以下内容:

[[ -f logfile ]] && program > devfile

@thatotherguy的注释的改编版本通过使用dd而不是Bash内部原理基本上相同:

program | dd conv=nocreat of=devfile

答案 1 :(得分:2)

Shell可以选择防止截断,但不能要求截断。

要获得FS级别的原子性,您需要使用不带open的{​​{1}} syscall。在脚本中执行此操作的一种方法是使用Python:

O_CREAT

答案 2 :(得分:2)

如果我没记错的话,Busybox默认使用ash shell,因此使用POSIX应该没问题。

重定向时,您可以选择截断(>)或追加(>>),但是如果文件不存在,内置的任何内容都将失败。要仅在POSIX中实现此目标,就需要通过管道实现一些功能。

append_if_exists() {
  [ -f "$1" ] || return 1
  cat >> "$1"
}

您可以这样使用它:

somecommand | append_if_exists /path/to/some.log

如果目标文件不存在,该函数将立即返回错误,并且从未打开过stdin,我应该相信应该将SIGPIPE发送回somecommand,然后终止。

请注意,这里有比赛-可以在[之后但在cat之前删除文件,从而导致重定向创建文件。但是随之而来的是,如果您需要原子性的东西,则可能需要以一种实际的编程语言重新考虑。

答案 3 :(得分:1)

设置noclobber选项,然后bash将拒绝覆盖现有文件

$ set -C    # or set -o noclobber
$ touch foo
$ cat bar > foo
bash: foo: cannot overwrite existing file

https://unix.stackexchange.com/questions/443595/bash-redirect-to-file-if-file-does-not-exist

答案 4 :(得分:0)

以下对我有用:

/* Printer device file must not be created if it does not
already exist. This is similar to `cat >', but open()
syscall is without O_CREAT. */

#include <fcntl.h> /* |open| */
#include <stdio.h> /* |fprintf| */
#include <unistd.h> /* |read| */

int main(int argc, char **argv)
{
  int fd;
  if ((fd = open(argv[1], O_WRONLY)) == -1) {
    fprintf(stderr, "open: %m\n");
    return 0;
  }

  char buf[8192];
  ssize_t n, m;

  while((n = read(0, buf, sizeof buf)) > 0) {
    m = write(fd, buf, n);
    if (m == -1) {
      fprintf(stderr, "write: %m\n");
      break;
    }
    if (m != n) {
      fprintf(stderr, "TODO: stuff all bytes in a loop\n");
      break;
    }
  }
  if (n == -1) fprintf(stderr, "read: %m\n");

  close(fd);
  return 0;
}