我正在编写一些用于执行 Linux shell 命令的应用程序代码,然后它将命令详细信息记录到 SQL 数据库中。这包括 STDOUT + STDERR 的输出(单独)。
执行命令后,假设进程没有输出任何内容...是否有任何理由将 STDOUT/STDERR 字段保留为 NULL -vs- 将它们设置为空字符串?
换句话说:这两件事在技术上有什么区别吗?
- 不向 STDOUT 输出任何内容的进程
- 一个向 STDOUT 输出空字符串(仅此而已)的进程
再次以另一种方式提出问题...在 SQL 中使这些列 NOT NULL 有意义吗?
答案1
在管道(std-err/out)中,没有空字符串的概念,它只是“无输出”;
> printf ''
> printf '' | xxd
其中 null 是某物
> printf '\0'
> printf '\0' | xxd
00000000: 00
在数据库中情况正好相反,少即是多,因此让您的脚本保持沉默(空字符串),并将数据库设置为空(空)。
答案2
不确定我理解这个问题,但是:
写入标准输出正在执行:
write(1, memory_address, length)
它将内存地址中存储的长度字节写入文件描述符 1(1 表示 stdout,2 表示 stderr)。例如,在echo test
, echo
(或 shell,如果echo
是内置的)中执行write(1, "test\n", 5)
.
不过,这有点傻,你可以用write()
长度为 0 来调用系统调用。
和:
write(1, address, 0)
至少在Linux上,系统调用仍然检查文件描述符是否已以写或读+写模式打开,并且该地址是否是有效地址(尽管它不必是可读的)。如果 stdout 是一个损坏的管道,我认为它不会导致 SIGPIPE 信号传递。
因此,执行大小为零并不严格等同于根本不执行任何写入,因为它可能会导致错误。
在实践中,我发现大多数命令都会避免使用“write()
如果可以”。
我发现这一点echo -n
并且在我尝试过的所有实现中都printf ''
没有进行任何系统调用。 write()
stdio 函数(fputs()
// printf()
...当您要求它们写入空字符串时fwrite()
不执行任何操作)。write()
要执行 0 长度写入,您可以尝试:
perl -e 'syswrite(STDOUT, "")'
或者
python -c 'import os; os.write(1, "")'
这些解释器中的原始接口是write()
.
例子:
$ strace -e write /bin/echo -n
$ strace -e write python -c 'import os; os.write(1, "")'
write(1, "", 0) = 0
$ python -c 'import os; os.write(1, "")' >&-
Traceback (most recent call last):
File "<string>", line 1, in <module>
OSError: [Errno 9] Bad file descriptor
$ python -c 'import os; os.write(1, "")' 1< /dev/null
Traceback (most recent call last):
File "<string>", line 1, in <module>
OSError: [Errno 9] Bad file descriptor
$ printf '%s\n' '#include <unistd.h>' 'main(){write(1,(char*)-1,0);}' | strace -e write tcc -run -
write(1, "", 0) = -1 EFAULT (Bad address)
$ printf '%s\n' '#include <unistd.h>' 'main(){write(1,(char*)0,1);}' | strace -e write tcc -run -
write(1, NULL, 1) = -1 EFAULT (Bad address)
$ printf '%s\n' '#include <unistd.h>' 'main(){write(1,(char*)0,0);}' | strace -e write tcc -run -
write(1, NULL, 0) = 0