这里文档基名冲突?

这里文档基名冲突?

我正在使用 EOF 生成运行 Rscript 的 bash 脚本。在 Rscript 中我用来basename指定输出文件名。

当我用来EOF生成 bash 脚本列表时,我无法开始basename工作。错误消息如下所示。我仍然能够生成 bash 脚本,但${AF}在它出现的两个地方都变成了空白。很奇怪!

我测试了 bash 脚本,它正在工作,所以我知道问题出在EOF和之间basename

我该如何使用basenamewith EOF?或者有什么替代方法吗?谢谢。

for letter in {A..Z}
      do cat <<- EOF > batch_${letter}.sh
    #!/bin/bash
    module load R/3.5.1
    R_func="/home/dir/R_func"
    TREAT="/home/dir/POP"
    BASE="/home/dir/base"
    OUTPUT="/home/dir/tmp"

    for AF in ${BASE}/${letter}*.txt_step3; do
    Rscript ${R_func}P_tools.R \
    --ptool ${R_func}/P_tools_linux \
    --group ${AF} \
    --treat ${TREAT}/pop_exclude24dup \
    --out ${OUTPUT}/OUT_$(basename ${AF%%_txt_step3})_noregress \
    --binary-target F; done

    EOF
       done

这是错误信息

基本名称:缺少操作数尝试“基本名称--help”以获取更多信息。

答案1

如果未引用分隔符,则命令替换(例如您的$(basename ...)和 变量)也会在此处文档中展开。你应该逃避它的$外部$(basename ...)以及$它里面的任何东西。

脚本的更正版本:

for letter in {A..Z}
        do cat <<- EOF > batch_${letter}.sh
                #!/bin/bash
                module load R/3.5.1
                R_func="/home/dir/R_func"
                TREAT="/home/dir/POP"
                BASE="/home/dir/base"
                OUTPUT="/home/dir/tmp"

                for letter in {A..Z} do {
                for AF in \${BASE}/${letter}*.txt_step3; do
                Rscript \${R_func}P_tools.R \
                --ptool \${R_func}/P_tools_linux \
                --group \${AF} \
                --treat \${TREAT}/pop_exclude24dup \
                --out \${OUTPUT}/OUT_\$(basename \${AF%%_txt_step3})_noregress \
                --binary-target F; done
                }
        EOF
done

这实际上是用制表符缩进的;这个愚蠢的 Web 界面正在将制表符变成空格,这可能会破坏<<-任何 POSIX shell 中的情况,它只是剥离制表符,而不是 EOF 分隔符之前的空格以及此处文档中的行。

答案2

<< EOF...构造EOF称为此处文档,您可以将任何您喜欢的字符串作为分隔符,但EOF很常见。

您面临的问题是,此处文档的行为类似于双引号字符串,因此其中的变量和命令替换在cat运行时会扩展,它们不会按原样存储在结果文件中。这可能不是您想要的,因为您设置了,例如R_func在您正在编写的中batch_x.sh,但会扩展到生成脚本中的${R_func}任何值。R_func

您可以通过引用here-doc分隔符来防止这种情况,即使用cat << 'EOF'。然而,这阻止了扩展全部变量,因此如果不分部分创建文件或使用不带引号的分隔符并转义除一个变量之外的所有变量,则不能扩展一个文件,而不能扩展其他变量,如比利叔叔的回答


现在,如果我正确理解你的想法,你想要创建 26 个脚本,每个字母都硬编码在其中一个脚本中。您创建的第一个脚本 ( batch_A.sh) 看起来像这样:

module load R/3.5.1
R_func="/home/dir/R_func"
....
for AF in ${BASE}/A*.txt_step3; do
   Rscript ${R_func}P_tools.R \
   ...
done

相反,您可以只创建一个脚本,如下所示,并将字母作为命令行参数传递给它。第一个命令行参数可用作"$1"

#!/bin/bash
module load R/3.5.1
R_func="/home/dir/R_func"
TREAT="/home/dir/POP"
BASE="/home/dir/base"
OUTPUT="/home/dir/tmp"
letter=$1

for AF in ${BASE}/${letter}*.txt_step3; do
    Rscript "${R_func}P_tools.R" \
    --ptool "${R_func}/P_tools_linux" \
    --group "${AF}" \
    --treat "${TREAT}/pop_exclude24dup" \
    --out "${OUTPUT}/OUT_$(basename "${AF%%_txt_step3}")_noregress" \
    --binary-target F;
done

letter现在将从命令行获取变量,因此您可以运行batch.sh A来处理A文件等。

相关内容