为什么 cat 命令重定向一个新文件会立即执行?

为什么 cat 命令重定向一个新文件会立即执行?

我想生成一个稍后可以调用的bash文件,就像这样

cat <<-SCRIPT >test-$$
        #!/bin/bash
        osType=$(grep -Po '^NAME="\K[^"]*' /etc/os-release)
        if [ "$osType" = ...]
        then
            ...
        fi
        exit
    SCRIPT

当我调试时,grep 命令总是以正确的方式执行,为什么?也尝试使用 awk 相同的错误

但如果我这样做

cat <<-SCRIPT >test-$$
        #!/bin/bash
        rpm -q somepackage > test-$$
        rm test-$$-lock
        exit
    SCRIPT

我没有看到 rpm 命令以正确的方式执行? test-$$ 和 test-$$-lock 也会有相同的 $$ 吗?

答案1

类似here-doc的<<-SCRIPT行为就像双引号字符串,因为扩展是在其中处理的。为了防止这种情况,请引用分隔符:

$ cat <<EOF
1+1 = $((1+1))
EOF

1+1 = 2

$ cat <<'EOF'
1+1 = $((1+1))
EOF

1+1 = $((1+1))

所以在这里:

cat <<-SCRIPT >test-$$
        ...
        osType=$(grep -Po '^NAME="\K[^"]*' /etc/os-release)

grep命令位于命令替换中,由于SCRIPT未加引号而被处理,因此在使用此处文档时会执行该命令。

另一方面,这里:

cat <<-SCRIPT >test-$$
        #!/bin/bash
        rpm -q somepackage > test-$$
        rm test-$$-lock
        exit
    SCRIPT

没有命令替换,因此没有命令运行。该rpm -q somepackage部分只是文本。但是,如果使用不带引号的分隔符,则$$此处文档内部将立即扩展为输出文件名称中使用的相同值。也就是说,如果当前 shell 的 PID 是 1234,则该cat命令将创建test-1234包含行rpm -q somepackage > test-1234.

使用带引号的分隔符,$$将保持原样,结果将被称为test-1234包含rpm -q somepackage > test-$$.如果您现在test-1234作为脚本运行,那么$$将会扩展,并且将使用 shell 的 PID。它可能与创建文件时使用的值不同。

无论如何,$$inrpm .. > test-$$rm test-$$-lock都会扩展到相同的值。

相关内容