【问题标题】:How to properly escaping qsub command with long input args within ssh command?如何在 ssh 命令中使用长输入参数正确转义 qsub 命令?
【发布时间】:2013-04-02 22:56:23
【问题描述】:

我有一个复杂的 qsub 命令要远程运行。

PROJECT_NAME_TEXT="TEST PROJECT"
PACK_ORGANIZATION="--source-organization \'MY, ORGANIZATION\'"
CONTACT_NAME="--contact-name \'Tom Riddle\'"
PROJECT_NAME_PACK="--project-name \"${PROJECT_NAME_TEXT}\""


INPUTARGS="${PACK_ORGANIZATION} ${CONTACT_NAME} ${PROJECT_NAME_PACK}"

ssh mycluster "qsub -v argv="$INPUTARGS" -l walltime=10:00:00 -l vmem=8GB -l nodes=1:ppn=4 /myscript_path/run.script" 

问题是远程集群无法识别 qsub 命令,它总是显示不正确的 qsub 命令,或者因为输入参数错误而总是在集群中排队。

一定是转义问题,我的问题是如何正确转义上面的命令?

【问题讨论】:

    标签: linux bash unix ssh


    【解决方案1】:

    尝试使用 here-doc 执行此操作:您有引号冲突(嵌套双引号是错误的):

    #!/bin/bash
    
    PROJECT_NAME_TEXT="TEST PROJECT"
    PACK_ORGANIZATION="--source-organization \'MY, ORGANIZATION\'"
    CONTACT_NAME="--contact-name \'Tom Riddle\'"
    PROJECT_NAME_PACK="--project-name \"${PROJECT_NAME_TEXT}\""
    
    
    INPUTARGS="${PACK_ORGANIZATION} ${CONTACT_NAME} ${PROJECT_NAME_PACK}"
    
    ssh mycluster <<EOF
    qsub -v argv="$INPUTARGS" -l walltime=10:00:00 -l vmem=8GB -l nodes=1:ppn=4 /myscript_path/run.script
    EOF
    

    如您所见,here-docs 对于带引号的输入非常有用。

    man bash | less +/'Here Documents'

    编辑

    来自您的 cmets:


    我使用了这种方法,但它给了我“不会分配伪终端,因为标准输入不是终端。”

    您可以使用

    忽略此警告
    ssh mycluster <<EOF 2>/dev/null
    

    (如果需要,请尝试将-t 切换为ssh


    如果你有

    -bash: line 2: EOF: command not found

    我认为您遇到了复制粘贴问题。尝试删除所有结束行上的多余空格


    而且这个方法似乎无法将本地变量$INPUTARGS 传递给远程集群

    这似乎与您的EOF 问题有关。


    $argv 在远程集群上不返回任何内容

    这是什么意思? $argv 不是bash 中的预定义变量。如果需要列出命令行参数,请使用预定义变量$@


    最后一件事:确保您使用的是bash

    【讨论】:

    • 哦,我不知道你可以在 bash 中使用 heredoc;我必须记住...
    • 我使用了这种方法,但它给了我“伪终端将不会被分配,因为标准输入不是终端。”和“-bash: line 2: EOF: command not found”
    • 而且这个方法似乎无法将本地变量 $INPUTARGS 传递给远程集群,$argv 在远程集群上什么也不返回。
    • @sputnick,是的,感谢您的回答和编辑。这两天我尝试了很多方法,但最终使用另一种方法将局部变量传递给远程,我的实际问题是我必须使用包含引号符号的参数,而在 bash 中这将始终被删除。我将发布最终可行的解决方案,我认为没有人在堆栈溢出时这样做。
    【解决方案2】:

    您的问题不是长度,而是引号的嵌套 - 在这一行中,您尝试在 " 中使用 ",但这是行不通的:

    ssh mycluster "qsub -v argv="$INPUTARGS" -l walltime=10:00:00 -l vmem=8GB -l nodes=1:ppn=4 /myscript_path/run.script"
    

    Bash 会将其视为"qsub -v argv=",然后是$INPUTARGS(未引用),然后是" -l walltime=10:00:00 -l vmem=8GB -l nodes=1:ppn=4 /myscript_path/run.script"

    反斜杠转义这些内引号可能会产生预期的效果,但在 bash 中嵌套引号会变得相当混乱。我经常尝试做的是在命令的开头添加一个echo,以显示扩展的各个阶段是如何展开的。例如

    echo 'As expanded locally:'
    echo ssh mycluster "qsub -v argv=\"$INPUTARGS\" -l walltime=10:00:00 -l vmem=8GB -l nodes=1:ppn=4 /myscript_path/run.script"
    echo 'As expanded remotely:'
    ssh mycluster "echo qsub -v argv=\"$INPUTARGS\" -l walltime=10:00:00 -l vmem=8GB -l nodes=1:ppn=4 /myscript_path/run.script"
    

    【讨论】:

      【解决方案3】:

      感谢所有答案,但是他们的方法不适用于我的情况。我必须自己回答这个问题,因为这个问题非常复杂,我从stackoverflow中现有的解决方案中得到了线索。

      在我的情况下,有两个问题必须解决。

      1. 将本地程序的参数传递给远程集群。 Here-doc 解决方案在这种情况下不起作用。

      2. 在远程集群上运行 qsub,使用 long 变量作为包含引号符号的参数。

      问题 1.

      首先,我要介绍一下我在本地机器上运行的脚本需要这样的参数:

      scripttoberunoncluster.py --source-organisation "My_organization_my_department" --project-name "MyProjectName"  --processes 4 /targetoutputfolder/
      

      真正的参数比上面的要长很多,所以所有的参数都必须发送到remote。它们以这样的文件形式发送:

      PROJECT_NAME="MyProjectName"
      PACK_ORGANIZATION="--source-organization '\\\"My_organization_my_department\\\"'" # multiple layers of escaping, remove all the spaces
      PROJECT_NAME_PACK="--project-name '\\\"${PROJECT_NAME}\\\"'"
      PROCESSES_="--processes 4"
      TARGET_FOLDER_PACK="/targetoutputfolder/"
      
      INPUTARGS="${PACK_ORGANIZATION} ${PROJECT_NAME_PACK} ${PROCESSES} ${TARGET_FOLDER_PACK}"
      
      echo $INPUTARGS > "TempPath/temp.par"
      scp "TempPath/temp.par" "remotecluster:/remotepath/"
      

      我的解决方案有点妥协。但是通过这种方式,远程集群可以运行参数包含引号的脚本。如果您没有将所有变量(作为参数)放在一个文件中并将其传输到远程集群,那么无论您如何将它们传递给变量,引号符号都将被删除。

      问题 2。

      检查 qsub 如何在远程集群上运行。

      ssh remotecluster "qsub -v argv=\"`cat /remotepath/temp.par`\" -l walltime=10:00:00 /remotepath/my.script"
      

      在 my.script 中:

      INPUT_ARGS=`echo $argv`
      
      python "/pythonprogramlocation/scripttoberunoncluster.py" $INPUT_ARGS ; #note: $INPUT_ARGS hasn't quote
      

      【讨论】:

        【解决方案4】:

        所描述的转义问题在于要求在两个评估过程之后保留参数周围的最终引号,即。 e.经过两次评估后,我们应该会看到如下内容:

        --source-organization "My_organization_my_department" --project-name "MyProjectName" --processes 4 /targetoutputfolder/
        

        这可以通过首先将每个参数放在一个单独的变量中,然后用单引号将参数括起来,同时确保参数字符串中可能的单引号被'\''“转义”(实际上,参数将被拆分为单独的字符串,但在使用时,split-up 参数将自动由 UNIX(POSIX?)shell 的字符串评估机制重新连接。这个过程必须重复 3 次。

        {
        escsquote="'\''"
        
        PROJECT_NAME="MyProjectName"
        
        myorg="My_organization_my_department"
        myorg="'${myorg//\'/${escsquote}}'" # bash
        myorg="'${myorg//\'/${escsquote}}'"
        myorg="'${myorg//\'/${escsquote}}'"
        PACK_ORGANIZATION="--source-organization ${myorg}"
        
        pnp="${PROJECT_NAME}"
        pnp="'${pnp//\'/${escsquote}}'"
        pnp="'${pnp//\'/${escsquote}}'"
        pnp="'${pnp//\'/${escsquote}}'"
        PROJECT_NAME_PACK="--project-name ${pnp}"
        
        PROCESSES="--processes 4"
        TARGET_FOLDER_PACK="/targetoutputfolder/"
        
        INPUTARGS="${PACK_ORGANIZATION} ${PROJECT_NAME_PACK} ${PROCESSES} ${TARGET_FOLDER_PACK}"
        
        echo "$INPUTARGS"
        eval echo "$INPUTARGS" 
        eval eval echo "$INPUTARGS"
        echo
        ssh -T localhost <<EOF
        echo qsub -v argv="$INPUTARGS" -l walltime=10:00:00 -l vmem=8GB -l nodes=1:ppn=4 /myscript_path/run.script
        EOF
        
        }
        

        欲了解更多信息,请参阅:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-29
          • 1970-01-01
          • 2021-11-11
          相关资源
          最近更新 更多