2011-07-06 33 views
6

Tôi có một tập lệnh, về bản chất là một trình bao bọc xung quanh một tệp thực thi có cùng tên trên một máy khác. Vì lợi ích của ví dụ, tôi sẽ bọc printf ở đây. Tập lệnh hiện tại của tôi trông giống như sau:Ngăn chặn ssh phá vỡ các tham số script shell

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

Thật không may, điều này vi phạm khi một trong các đối số chứa khoảng trắng, ví dụ: tôi hy vọng các lệnh sau đây sẽ cung cấp cho các kết quả giống hệt nhau .:

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

Sự cố càng trở nên tồi tệ hơn khi có (thoát) dòng mới. Làm thế nào tôi có thể thoát khỏi những lý lẽ của tôi ở đây?

Trả lời

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

Điều này phù hợp với không gian. Nó không hoạt động nếu đối số có một dấu nháy đơn được nhúng.

+0

Điều đó sẽ hoạt động, cảm ơn bạn. Tôi sẽ đăng một câu trả lời bổ sung mà cũng sửa chữa các vấn đề báo giá. – Ondergetekende

7

Dựa trên câu trả lời từ Peter Lyons, mà còn cho phép dấu ngoặc kép bên trong đối số:

#!/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}" 

này làm việc cho tất cả mọi thứ tôi đã thử nghiệm cho đến nay, ngoại trừ dòng mới:

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

Dường như làm việc cho các dòng mới (mặc dù dòng mới gây ra quirks hiển thị lạ khác trên thiết bị đầu cuối nếu chúng hiển thị ở vị trí sai) – Glyph

2

Bắt trích dẫn đúng là khá khó khăn và làm nó trong bash (một cách tổng quát và mạnh mẽ) gần như không thể.

Sử dụng Perl:

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

Dựa trên câu trả lời từ Koert và Peter Lyons, ở đây một wrapper cho ssh; tôi gọi nó là "sshsystem". (cũng có sẵn tại 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[@]}" 
Các vấn đề liên quan