防止ssh破坏shell脚本参数

我有一个脚本,本质上是一个可执行文件在另一台机器上的相同名称的包装。 为了举例,我将在这里包装printf。 我目前的脚本如下所示:

#!/bin/bash ssh user@hostname.tld. printf "$@" 

不幸的是,当其中一个参数包含一个空格时,这会中断,例如我期望以下命令给出相同的输出:

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

涉及(逃脱)新行时,问题变得更糟。 我怎样才能在这里正确地逃避我的论点?

 #!/bin/sh QUOTE_ARGS='' for ARG in "$@" do QUOTE_ARGS="${QUOTE_ARGS} '${ARG}'" done ssh user@hostname.tld. "${QUOTE_ARGS}" 

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

根据Peter Lyons的回答,也可以在内部引用引述:

 #!/bin/bash QUOTE_ARGS='' for ARG in "$@" do ARG=$(printf "%q" "$ARG") QUOTE_ARGS="${QUOTE_ARGS} $ARG" done ssh user@hostname.tld. "printf ${QUOTE_ARGS}" 

这工作到目前为止我测试的一切,除了换行符:

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

正确引用是非常困难的,用bash(以一般和强大的方式)做几乎是不可能的。

使用Perl:

 #!/usr/bin/perl use Net::OpenSSH; my $ssh = Net::OpenSSH->new('user@hostname'); $ssh->system('printf', @ARGV); 

根据Koert和Peter Lyons的答案,这里是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 # user@host 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[@]}"