GNU Parallel -q 选项导致 BCP "unknown option" 错误(本地主机和远程主机上的字符串引号不同)

GNU Parallel -q option causing BCP "unknown option" errors (different string quotes on local vs remote hosts)

在使用 gnu parallel 使用 mssql-tools 中的 bcp 分发导出作业时看到非常奇怪的行为。 当对 parallel 使用 -q 选项时,字符串在本地主机上的解释与在远程主机上的解释不同。

运行 仅作为本地主机上文件的循环,bcp 进程不会抛出任何错误

但是,使用 parallel 分发文件导出时,bcp 进程在本地主机 上执行 抛出

/opt/mssql-tools/bin/bcp: unknown option

错误,而在 远程主机 上执行的错误(通过 --sshloginfile 参数)成功完成。 运行 的基本代码看起来像...

# setting some vars to pass
TO_SERVER_ODBCDSN="-D -S MyMSSQLServer"
TO_SERVER_IP="-S 172.18.54.22"
DB="$dest_db" #TODO: enforce being more careful with this value
TABLE="$tablename" # MUST exist beforehand, case matters
USER=$(tail -n+1 $source_home/mssql-creds.txt | head -1)
PASSWORD=$(tail -n+2 $source_home/mssql-creds.txt | head -1)
DATAFILES="/some/path/to/files/"
TARGET_GLOB="*.tsv"
RECOMMEDED_IMPORT_MODE='-c' # makes a HUGE difference, see 
DELIMITER="\\t" # (currently not used) DO NOT use format like "'\t'", nested quotes seem to cause hard-to-catch error, want "\t" literal

....

bcpexport() {
    filename=
    TO_SERVER_ODBCDSN=
    DB=
    TABLE= # MUST exist beforehand, case matters
    USER=
    PASSWORD=
    RECOMMEDED_IMPORT_MODE= # makes a HUGE difference, see 
    DELIMITER= # not currently used
    WORKDIR=
    LOGDIR=

    ....

    /opt/mssql-tools/bin/bcp "$TABLE" in "$localfile" \
        $TO_SERVER_ODBCDSN \
        -U $USER -P $PASSWORD \
        -d $DB \
        $RECOMMEDED_IMPORT_MODE
        -t "\t" \
        -e ${localfile}.bcperror.log
}

export -f bcpexport
parallelization_pernode=5
parallel -q -j $parallelization_pernode \
        --sshloginfile $source_home/parallel-nodes.txt \
        --env bcpexport \
        bcpexport {} "$TO_SERVER_ODBCDSN" $DB $TABLE $USER $PASSWORD $RECOMMEDED_IMPORT_MODE $DELIMITER $workingdir $logdir \
        ::: $DATAFILES/$TARGET_GLOB  #from hdfs nfs gateway

查看进程的 bash 解释(通过 运行ning ps -aux | grep bcp 在主机上 parallel--sshloginfile 中给出)对于我们看到的远程主机...

/bin/bash -c bcpexport() { ... /opt/mssql-tools/bin/bcp "$TABLE" in "$localfile" $TO_SERVER_ODBCDSN -U $USER -P $PASSWORD -d $DB $RECOMMEDED_IMPORT_MODE;  -t "\t" -e ${localfile}.bcperror.log; ...

对于本地主机,bash 解释是...

/bin/bash -c bcpexport() { ... /opt/mssql-tools/bin/bcp "$TABLE" in "$localfile" $TO_SERVER_ODBCDSN -U $USER -P $PASSWORD -d $DB $RECOMMEDED_IMPORT_MODE;  -t "\t" -e ${localfile}.bcperror.log; ...

也就是说,它们看起来一样。

我目前的想法是 bcp 命令中的“\t”被以有问题的方式解释。在不使用 -q 选项的情况下调试 parallel 我们看到...

$ parallel -j 5 --sshloginfile ./parallel-nodes.txt echo "Number {}: Running on \`hostname\`: \t" ::: 1 2 3 4 5              
Number 4: Running on HW04.ucera.local: t
Number 1: Running on HW04.ucera.local: t
Number 2: Running on HW03.ucera.local: t
Number 5: Running on HW03.ucera.local: t
Number 3: Running on HW02.ucera.local: t
$ parallel -q -j 5 --sshloginfile ./parallel-nodes.txt echo "Number {}: Running on \`hostname\`: \t" ::: 1 2 3 4 5           
Number 1: Running on `hostname`:    
Number 4: Running on `hostname`:    
Number 3: Running on `hostname`: \t
Number 2: Running on `hostname`: \t
Number 5: Running on `hostname`: \t

bcp 命令需要 "\t" 文字而不是 "t" 文字(我怀疑其他几个类似的字符串损坏(而且我确实相信 \t 是 bcp 的默认值,但这是只是一个例子,想保留 \t 以便代码清晰)),但不确定如何为 本地和远程节点获得此 ,甚至不知道为什么这种行为因远程与本地而异。

基本上,需要本地和远程主机的字符串完全相同,即使字符串中有空格或转义字符(注意,我认为这曾经是并非如此(在其他机器上有较旧的脚本没有这个问题))

不确定这是 parallel 问题还是 bcp 问题(目前认为 parallel 中的 -q 选项出了问题,但不确定)。任何人有任何调试建议或修复?关于可能发生的事情的想法?

首先,hostname没有展开的原因是-q。它引用 ` 使其不会扩展。

其次,我认为您看到的是内置 echo/bin/echo 中的不同行为。内置 echo 取决于 shell。这里我比较echo \\t在不同的shells:

$ parallel --onall --tag -S sh@lo,bash@lo,csh@lo,tcsh@lo,ksh@lo,zsh@lo echo  \\t ::: a 
bash@lo \t a
tcsh@lo          a
sh@lo    a
ksh@lo \t a
zsh@lo   a
csh@lo \t a

但是,这并不能使您更接近解决方案。如果我是你,我会使用 env_parallel 来复制环境变量。如果远程系统上的登录 shell 与您的 shell 不同,则设置 PARALLEL_SHELL 以强制使用 shell.

所以:

#!/bin/bash

env_parallel --session

# setting some vars to pass
TO_SERVER_ODBCDSN="-D -S MyMSSQLServer"
:
:
PARALLEL_SHELL=bash env_parallel -q -j $parallelization_pernode ...
(no need to use neither --env nor 'export -f' when using 'env_parallel --session')

# Cleanup (not needed if this is the last line in the script)
env_parallel --end-session