ssh/su -c에 대한 bash 명령 및 인수를 작성하는 방법

ssh/su -c에 대한 bash 명령 및 인수를 작성하는 방법

다음과 같은 단순화된 버전과 같이 소스 배열 목록에서 항목을 백업하고 있습니다.

sources=( file1 file2 "other stuff" )
backupcommand="rsync -ar ${a[@]} dest/"
su backupuser -c "$backupcommand"

$backupcommand올바른 이스케이프를 사용하면 문제가 발생합니다. 위의 의미는 rsync가 "other stuff"라는 파일이 아닌 "other"라는 파일과 "stuff"라는 다른 파일을 찾는다는 것입니다.

인용된 명령 sh -c ...(또는 ssh ...무엇이든)을 어떻게 구성할 수 있습니까? 나는 배쉬를 사용하고 있습니다.

답변1

먼저, bash 배열의 내용을 표시할 방법이 필요합니다 sources. 좋은 접근 방식 printf '%s\n' <args>은 .NET의 각 인수에 대해 한 줄을 출력하는 것을 사용하는 것 같습니다 <args>.

예를 들어:

$ sources=( file1 file2 "other stuff" )
$ printf '%s' "${sources[@]}"
file1
file2
other stuff

이것을 명령으로 사용하면 백업 프로그램(예를 들어)이 실제로 인수로 수신하는 내용을 backupcommand확인할 수 있습니다 . 따라서 (or )를 통해 실행하려는 명령이 이고 두 개의 인수가 있다고 rsync가정해 보겠습니다 .bash -c ...ssh ...printf '%s\n' <args>file1other stuff

우리는 대상 셸에서 이 명령을 실행하려고 합니다.

$ printf '%s\n' file1 other\ stuff
file1
other stuff

그러므로 이것을 논증으로 활용하기 위해서는 인용이 필요하다. 우리는 인용하기 위해 ""or ''or를 사용할 수 있습니다 \. printf '%s\n'이 작업을 성공적으로 수행했는지 확인하기 위해 다시 사용할 수 있습니다 .

$ # With backslashes:
$ printf '%s\n' printf\ \'%s\\n\'\ file1\ other\\\ stuff
printf '%s\n' file1 other\ stuff

$ # With single quotes
$ printf '%s\n' 'printf '\''%s\n'\'' file1 other\ stuff'
printf '%s\n' file1 other\ stuff

$ # Using a variable to store the command...
$ the_command='printf '\''%s\n'\'' file1 other\ stuff'
$ # ..then using that variable as a single argument...
$ printf '%s\n' "$the_command"
printf '%s\n' file1 other\ stuff

지금까지는 너무 좋았습니다. 이전 버전에서는 명령이 포함된 변수를 참조했습니다.

이제 배열을 매개변수로 사용할 수 있나요? 우리가 해야 할 일은 배열의 각 항목을 인용/이스케이프하고 단일 string 에 추가하는 것입니다 the_command.

${var[@]}각 배열 항목에 대해 토큰을 생성하도록 bash에 지시합니다. 그러나 이는 이미 해석되었기 때문에 이스케이프되지 않습니다. 따라서 이를 쉘 명령 문자열에 넣을 수는 없습니다. 따라서 참조를 적용하는 방법이 필요합니다.

Bash는 printf '%q' arg인용되어야 합니다 arg. 명령 대체를 사용할 수 있습니다.$(...)

$ sources=( file1 other\ stuff )
$ the_command=printf\ \'%s\\n\'
$ for item in "${sources[@]}"
  do the_command="$the_command "$(printf '%q' "$item")
  done
$ printf '%s\n' "$the_command"
printf '%s\n' file1 other\ stuff

오랫동안 살다! 그러나 다음과 같이 정리할 수 있습니다.

$ sources=( file1 other\ stuff )
$ the_command="printf '%s\\n'"$(printf ' %q' "${sources[@]}")
$ printf '%s\n' "$the_command"
printf '%s\n' file1 other\ stuff

$ # And as final proof...
$ bash -c "$the_command"
file1
other stuff

원래 질문에 적용됩니다.

sources=( file1 file2 "other stuff" )
backupcommand="rsync -ar "$(printf ' %q' "${sources[@]}")" dest/"
su backupuser -c "$backupcommand"

일반화하다

  • printf '%q' arg인용 부호arg
  • 명령 대체는 $(...)명령 출력을 기반으로 단일 토큰을 생성합니다.
  • 다양한 인용/이스케이프 방법을 사용할 수 있습니다. 가장 읽기 쉬운 방법을 선택하세요.

답변2

아래와 같이 배열 주위에 이스케이프된 따옴표를 추가해 보세요.

backupcommand="rsync -ar \"${a[@]}\" dest/"

관련 정보