容器标准输出重定向至文件失效原因及shell形式CMD疑问
问题1:为什么重定向未生效,test.log未生成?
这是完全正常的,问题出在你使用了exec形式的entrypoint(数组写法)。当你用数组形式定义entrypoint或command时,Docker会直接执行指定的程序,不会通过shell来解析命令。这时候你写的>和test.log会被当作普通参数传递给/test.sh脚本,而不是被shell解析为重定向操作。
你的脚本test.sh里没有处理这些参数,所以自然不会生成test.log,输出还是会直接打印到容器的标准输出(也就是你用docker-compose up看到的内容)。
解决方法有两种:
- 使用shell形式(字符串写法):把
entrypoint改成字符串,让Docker自动用/bin/sh -c来执行命令,这样shell会解析重定向:entrypoint: "/test.sh > test.log" - 显式调用shell(exec形式):在数组里直接指定shell来执行命令,这样也能让shell解析重定向:
entrypoint: ["sh", "-c", "/test.sh > test.log"]
问题2:为什么command: /test.sh > /test.log不生效,但command: ["sh", "-c", "/test.sh > /test.log"]生效?
你的理解本身是对的:shell形式的CMD/ENTRYPOINT确实等价于用sh -c包裹命令,但问题出在YAML的解析和Compose的处理逻辑上。
当你写command: /test.sh > /test.log时,YAML会把这个字符串拆分成多个部分(因为有空格和特殊符号>),Compose最终会把它转换成exec形式的数组:["/test.sh", ">", "/test.log"]。这就回到了第一个问题的情况——重定向符号被当作参数传递,而不是被shell解析,所以自然不生效。
要让shell形式生效,你需要把整个命令用引号括起来,告诉YAML和Compose这是一个完整的字符串:
command: "/test.sh > /test.log"
这时候Compose会把它当作shell形式的命令,Docker会自动用/bin/sh -c "/test.sh > /test.log"来执行,重定向就会正常工作了。而你用["sh", "-c", "/test.sh > /test.log"]是显式地调用shell,shell会直接解析里面的重定向逻辑,所以也能生效。
内容的提问来源于stack exchange,提问作者SangminKim

