2011-07-06 175 views
6

我有一个脚本,它基本上是一个可执行文件在不同机器上的相同名称的包装。为了举例,我会在这里包装printf。我当前的脚本如下所示:防止ssh破坏shell脚本参数

#!/bin/bash 
ssh [email protected] printf "[email protected]" 

不幸的是,如果其中一个参数包含空格,我期望以下命令给出相同的输出。:

~$ ./wrap_printf "%s_%s" "hello world" "1" 
hello_world1_ 
~$ printf "%s_%s" "hello world" "1" 
hello world_1 

当涉及(逃逸)换行符时,问题变得更糟。我在这里如何正确地逃避我的论点?

回答

5
#!/bin/sh 
QUOTE_ARGS='' 
for ARG in "[email protected]" 
do 
    QUOTE_ARGS="${QUOTE_ARGS} '${ARG}'" 
done 
ssh [email protected] "${QUOTE_ARGS}" 

这适用于空间。如果参数具有嵌入式单引号,则不起作用。

+0

这将工作,谢谢。我会发布一个额外的答案,这也解决了报价问题。 – Ondergetekende

7

基于从彼得里昂的答案,但也允许引号内的参数:

#!/bin/bash 
QUOTE_ARGS='' 
for ARG in "[email protected]" 
do 
    ARG=$(printf "%q" "$ARG") 
    QUOTE_ARGS="${QUOTE_ARGS} $ARG" 
done 

ssh [email protected] "printf ${QUOTE_ARGS}" 

这适用于一切我到目前为止测试,除了换行:

$ /tmp/wrap_printf "[-%s-]" "hello'\$t\"" 
[-hello'$t"-] 
+0

似乎也适用于换行符(尽管换行符在终端出现错误的地方会导致其他奇怪的显示怪癖) – Glyph

2

获取报价权是非常困难的,并在bash(以一般和强大的方式)几乎不可能。

使用Perl:

#!/usr/bin/perl 
use Net::OpenSSH; 
my $ssh = Net::OpenSSH->new('[email protected]'); 
$ssh->system('printf', @ARGV); 
0

基于从Koert和彼得·莱昂斯,这里SSH的包装问题的答案;我称之为“sshsystem”。 (也可在https://gist.github.com/4672115

#!/bin/bash 

# quote command in ssh call to prevent remote side from expanding any arguments 
# uses bash printf %q for quoting - no idea how compatible this is with other shells. 
# http://stackoverflow.com/questions/6592376/prevent-ssh-from-breaking-up-shell-script-parameters 

sshargs=() 

while (($# > 0)); do 
    case "$1" in 
    -[1246AaCfgKkMNnqsTtVvXxYy]) 
     # simple argument 
     sshargs+=("$1") 
     shift 
     ;; 
    -[bcDeFIiLlmOopRSWw]) 
     # argument with parameter 
     sshargs+=("$1") 
     shift 
     if (($# == 0)); then 
      echo "missing second part of long argument" >&2 
      exit 99 
     fi 
     sshargs+=("$1") 
     shift 
     ;; 
    -[bcDeFIiLlmOopRSWw]*) 
     # argument with parameter appended without space 
     sshargs+=("$1") 
     shift 
     ;; 
    --) 
     # end of arguments 
     sshargs+=("$1") 
     shift 
     break 
     ;; 
    -*) 
     echo "unrecognized argument: '$1'" >&2 
     exit 99 
     ;; 
    *) 
     # end of arguments 
     break 
     ;; 
    esac 
done 


# [email protected] 
sshargs+=("$1") 
shift 

# command - quote 
if (($# > 0)); then 
    # no need to make COMMAND an array - ssh will merge it anyway 
    COMMAND= 
    while (($# > 0)); do 
     arg=$(printf "%q" "$1") 
     COMMAND="${COMMAND} ${arg}" 
     shift 
    done 
    sshargs+=("${COMMAND}") 
fi 

exec ssh "${sshargs[@]}"