ssh 호스트 bash -c를 통해 실행되는 명령에서 ls 매개변수가 작동하지 않는 것처럼 보이는 이유는 무엇입니까?

ssh 호스트 bash -c를 통해 실행되는 명령에서 ls 매개변수가 작동하지 않는 것처럼 보이는 이유는 무엇입니까?

저는 Ubuntu를 실행하는 로컬 호스트와 원격 호스트가 있고 쉘은 bash로 설정되어 있습니다. 내 홈 디렉토리에는 로컬 호스트와 원격 호스트에 두 개의 파일 file-1및 이 있습니다 . 각 홈 디렉토리에는 몇 가지 다른 파일이 있으며 일치하는 파일만 나열하고 싶습니다 .file-2remotefile-*

로컬에서는 다음과 같은 예상 결과가 생성됩니다 file-1 file-2.

$ ls file-*
$ bash -c 'ls file-*'

그러나 이 명령은 원격 홈 디렉터리의 모든 파일을 반환합니다. 거기서 무슨 일이 일어 났어?

$ ssh remote bash -c 'ls file-*'
$ ssh remote bash -c 'ls "file-*"'
$ ssh remote bash -c 'ls file-\*'
$ ssh remote bash -c 'ls "file-\*"'

ssh remote 'ls file-*'이것이 예상한 결과 만 생성한다는 것을 알고 있지만 ssh remote bash -c 'ls ...'전달된 인수가 폐기된 것처럼 보이는 이유는 무엇입니까 ls ...? (원격으로 실행된 ls의 출력도 파이프하여 전달되었으므로 ls해당 출력만 영향을 받는 것 같습니다 ssh remote bash -c 'ls file-* | xargs -I {} echo "Got this: {}"'.)

답변1

사용할 때 원격 호스트에서 실행되는 명령은 ssh remote bash -c 'ls file-*'다음과 같습니다.

bash -c ls file-*

이는 bash -c스크립트를 실행하는 것을 의미합니다 ls. 위치 인수로서 bash -c스크립트는 원격 호스트에서 일치하는 이름을 가져옵니다 file-*(이 이름 중 첫 번째 이름은 에 배치되므로 $0실제로 위치 인수의 일부가 아닙니다). 인수는 명령에 전달되지 않으므로 ls디렉터리의 모든 이름이 나열됩니다.

ssh첫 번째 수준 따옴표(명령줄에서 사용되는 외부 따옴표 집합)를 제거하고 원격 호스트에서 실행할 명령을 전달합니다. 호출한 셸은 ssh이러한 따옴표를 제거하고 ssh원격 명령의 인수를 구분하기 위해 새 따옴표를 삽입하지 않습니다(명령에서 사용되는 따옴표를 방해할 수 있으므로).

다음 명령을 사용하면 이를 확인할 수 있습니다 ssh -v.

[...]
debug1: Sending command: bash -c ls file-*
[...]

표시되는 다른 세 가지 명령은 동일한 방식으로 작동하지만 shell 등이 아닌 $0string 에만 설정됩니다 .file-*$1$2bash -c

아마도 당신이 원하는 것은 전체 명령을 인용하는 것입니다.

ssh remote 'bash -c "ls file-*"'

ssh -v디버그 출력 에서는 다음과 같이 보고됩니다.

[...]
debug1: Sending command: bash -c "ls file-*"
[...]

즉, 원격 명령으로 전달된 문자열이 따옴표를 제거한 후 로컬 셸에서 실행하려는 명령인지 확인해야 합니다.

당신은 또한 사용할 수 있습니다

ssh remote bash -c \"ls file-\*\"

또는

ssh remote bash -c '"ls file-*"'

답변2

나는 ssh 매개변수가 서버에 의해 직접 실행될 것으로 기대한다는 오해가 있다고 생각하지만 이는 사실이 아닙니다. 당신이 쓸 때 :

ssh remote bash -c 'ls file-*'

SSH 클라이언트는 bash, -c및 를 공백으로 ls file-*연결 하여 bash -c ls file-*서버로 보냅니다. 서버는 해당 문자열을 가져와 매개변수로 전달합니다 bash -c(원격 셸인 경우). 즉, 서버에서 다음과 같은 작업을 수행하게 됩니다.

bash -c 'bash -c ls file-*'

straceSSH 서버에서 다음 명령을 실행하여 이를 확인할 수 있습니다.

$ sudo strace -fe trace=execve -p "$(pgrep -o sshd)" |& grep bash
[pid 794417] execve("/bin/bash", ["bash", "-c", "bash -c ls files-*"], 0x560ab66915d0 /* 13 vars */) = 0

내 생각에 당신이 원하는 것은 다음과 같습니다.

ssh remote 'ls file-*'

서버가 실행할 수 있도록:

bash -c 'ls file-*'

관련 정보