Linux 将envsubt与tee结合使用会随机生成一个空文件

Linux 将envsubt与tee结合使用会随机生成一个空文件,linux,bash,docker,tee,envsubst,Linux,Bash,Docker,Tee,Envsubst,我希望了解在一个简单的脚本中发生了什么,它似乎会产生随机结果 我想做的是: 从环境中定义的值替换预先存在的文件中的变量 这是在Docker容器中使用bash脚本完成的,该脚本运行以下命令: envsubst'$VAR1$VAR2'“$file”的命令替换原子(假设没有跨越任何文件系统边界)mv命令。还有scape命令,它允许您编写envsubs

我希望了解在一个简单的脚本中发生了什么,它似乎会产生随机结果

我想做的是:

  • 从环境中定义的值替换预先存在的文件中的变量

  • 这是在Docker容器中使用bash脚本完成的,该脚本运行以下命令:

    envsubst'$VAR1$VAR2'<$FILE | tee$FILE


发生了什么:

  • 有时所讨论的
    $文件
    在命令之前有内容,但在命令之后没有内容

如何重现该问题:

  • Dockerfile:
  • Bash脚本:

管道是异步的,您已经引入了竞争条件。您无法预测
envsubt
是否在
tee
截断之前或之后读取
$FILE

正确的方法是将更改写入临时文件,然后在成功后用临时文件替换原始文件

tmp=$(mktemp)
envsubst < "$FILE" > "$tmp" &&  mv "$tmp" "$FILE"
tmp=$(mktemp)
envsubst<“$FILE”>“$tmp”和&mv“$tmp”“$FILE”

您不需要将文件读入内存来测试它是否为空<代码>如果[!-s“$FILE”];然后,一个问题是,
$FILE
是指向某个文件的符号链接。这一点很好。您可以使用类似于
cat“$tmp”>“$file”
的命令替换原子(假设没有跨越任何文件系统边界)
mv
命令。还有
scape
命令,它允许您编写
envsubs<“$file”| scape“$file”
因为
海绵
在读取所有输入之前不会打开文件进行写入。(我通常不会提及它,因为1)它是非标准的,2)我只是没有使用它的实际经验。)
#!/bin/bash

mkdir -p /test

export TEST1=1
export TEST2=2
export TEST3=3

for I in {1..300} ; do
    echo '$TEST1 $TEST2 $TEST3' > /test/file-$I
done

for FILE in /test/file-* ; do
    envsubst < $FILE | tee $FILE
done

for FILE in /test/file-* ; do
    if [[ -z "$(cat $FILE)" ]]; then
        echo "$FILE is empty!"
        FAIL=1
    fi
done

if [[ -n "$FAIL" ]]; then
    exit 2
fi
...
/test/file-11 is empty!
/test/file-180 is empty!
/test/file-183 is empty!
/test/file-295 is empty!
tmp=$(mktemp)
envsubst < "$FILE" > "$tmp" &&  mv "$tmp" "$FILE"