스크립트에서 공백이 포함된 문자열을 올바르게 바꾸는 방법

스크립트에서 공백이 포함된 문자열을 올바르게 바꾸는 방법

내 스크립트에는 다음이 있습니다.

sshkey="/Users/me/some path/with spaces/id_rsa"
dstport=...
dstparent=...
dstuserhost=...

rsync -az --delete -e "ssh -i $sshkey -p $dstport" $src $dstuserhost:$dstparent

내가 그것을 실행하면 나는 얻는다 :

rsync: "/Users/me/some"에 대한 link_stat 실패: 해당 파일 또는 디렉터리 없음 (2)

답변1

주위에 작은따옴표를 추가하면 $sshkey문제가 해결됩니다.

rsync -az --delete -e "ssh -i '$sshkey' -p '$dstport'" "$src" "$dstuserhost:$dstparent"

$sshkey은 큰따옴표로 묶인 문자열 내에 있기 때문에 호출 전에 대화형 셸에 의해 확장되지만 작은따옴표는 rsync연결을 설정하기 위해 호출이 이루어질 때 문자열이 더 이상 분할되는 것을 방지합니다.rsyncssh

$sshkey자체에는 작은따옴표 문자가 포함되어 있지 않다고 가정합니다 .

답변2

"내부" 따옴표를 삽입해야 합니다. 내가 말할 것

printf -v rsh_cmd 'ssh -i "%s" -d "%s"' "$sshkey" "$dstport"
...
rsync ... -e "$rsh_cmd"

답변3

-e이 옵션에 대한 인수는 rsync쉘 명령줄이 아니라 rsync명령줄입니다. rsyncBourne 쉘과 다른 자체 규칙을 사용하여 구문 분석됩니다.

모든 쉘과 마찬가지로 공백 문자를 매개변수 구분 기호로 처리하고 Bourne 쉘과 마찬가지로 작은따옴표와 큰따옴표(백슬래시 제외)를 인용 연산자로 처리합니다. 셸 확장(예 $var: $(cmd), , *.txt, ~user...) 은 수행하지 않습니다 .

따라서 해당 의사 명령줄에 임의의 인수를 포함하려면 큰따옴표 문자 자체(작은따옴표로 묶임)를 제외하고 인수를 큰따옴표로 묶거나 작은따옴표로 묶을 수 있습니다. 작은따옴표 문자 자체의 경우(큰따옴표로 묶임)

예를 들어 SSH 키 파일이 이면 /cygdrive/c/John Doe/.ssh/John "Dude" Doe's.rsa매개변수 는 또는 -e와 유사해야 합니다 .'/cygdrive/c/John Doe/.ssh/John "Dude" Doe'"'"'s.rsa'"/cygdrive/c/John Doe/.ssh/John "'"'"Dude"'"'" Doe's.rsa"

이를 수행하기 위해 전용 함수를 정의할 수 있습니다.재동기화 참조좋다:

# ksh93/bash/zsh syntax:
rsync_quote() {
  local arg="$1"
  arg=${arg//\'/\'\"\'\"\'}
  printf "'%s'\n" "$var"
}

rsync -e "ssh -i $(rsync_quote "$sshkey") -p $dstport" ...

또 다른 옵션은 쉘을 인수로 전달한 다음 명령줄을 -e해석하는 것입니다 . ssh이것의 한 가지 장점은 쉘이 변수 확장을 할 수 있다는 것입니다.

KEY=$sshkey PORT=$dstport SSH_COMMAND='ssh -i "$KEY" -p "$PORT" "$@"' \
  rsync -e "sh -c 'eval \"\$SSH_COMMAND\"' sh" ...

: 으로 실행하면 strace -fe execve -s 999다음과 같이 확장되는 것을 볼 수 있습니다.

execve("/usr/bin/rsync", ["rsync", "-e", "sh -c 'eval \"$SSH_COMMAND\"' sh", "1/", "localhost:2/"], 0x7ffc03b83678 /* 74 vars */) = 0
strace: Process 7208 attached
[pid  7208] execve("/bin/sh", ["sh", "-c", "eval \"$SSH_COMMAND\"", "sh", "localhost", "rsync", "--server", "-e.LsfxC", ".", "2/"], 0x7ffcc6ad0f28 /* 74 vars */) = 0
[pid  7209] execve("/usr/bin/ssh", ["ssh", "-i", "/cygdrive/c/John Doe/.ssh/John \"Dude\" Doe's.rsa", "-p", "2222", "localhost", "rsync", "--server", "-e.LsfxC", ".", "2/"], 0x5651a0c144a8 /* 74 vars */) = 0

관련 정보