簡體   English   中英

防止ssh分解shell腳本參數

[英]Prevent ssh from breaking up shell script parameters

我有一個腳本,它本質上是對不同機器上同名可執行文件的包裝。 為了舉例,我將在這里包裝 printf。 我當前的腳本如下所示:

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

不幸的是,當 arguments 之一包含空格時,這會中斷,例如,我希望以下命令提供相同的輸出:

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

當涉及(轉義的)換行符時,問題會變得更糟。 我如何在這里正確地轉義我的 arguments ?

根據 Peter Lyons 的回答,但也允許在 arguments 內引用:

#!/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"-]
#!/bin/sh
QUOTE_ARGS=''
for ARG in "$@"
do
  QUOTE_ARGS="${QUOTE_ARGS} '${ARG}'"
done
ssh user@hostname.tld. "${QUOTE_ARGS}"

這適用於空間。 如果參數有嵌入的單引號,它就不起作用。

正確引用是非常困難的,並且在 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[@]}"

最簡單和最快的是只使用 Bash 的引用參數轉換: ${parameter@Q} 這可以在使用${array[@]@Q}的數組擴展期間自動應用,但是當使用內置參數數組時,名稱和括號被刪除,因此它變成${@@Q} 因此,原始腳本只需要添加 4 個字符即可工作。

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

現在任何 escaping 都可以工作,即使是這樣的終端 colors:

./wrap_printf "%s\e[39m\e[49m\n" $'\e[30m\e[42mBlack on Green' "Just Normal Text"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM