아래 예를 무엇으로 설명할 수 있으며 곡예에 대한 과도한 언급 없이 이 문제를 해결하는 방법은 무엇입니까? $n
실제 문제에 주의가 산만해지는 경우를 대비하여 여러 줄의 명령 문자열을 시뮬레이션하는 데 사용하고 있습니다 .
~$ n=$'\n'; sudo -i echo "line1${n}line2${n}"
line1line2
~$
하지만
~$ n=$'\n'; sudo echo "line1${n}line2${n}"
line1
line2
~$
답변1
strace에서 실행하면 sudo -i echo $'line1\nline2'
Bash가 다음과 같이 시작되는 방법이 표시됩니다.
9183 execve("/bin/bash", ["-bash", "--login", "-c", "echo line1\\\nline2\\\n"], ...
이제 strace
문자열을 표시할 때 특수 문자는 백슬래시 이스케이프와 함께 표시되므로 Bash가 실제로 인수로 얻는 것은 -c
셸의 경우 연속된 줄을 표시하는 후행 백슬래시이며 백슬래시와 그 뒤의 백슬래시는 개행 문자가 제거됩니다.echo line1[backslash][newline]line2[backslash][newline]
아니요 -i
, 셸을 거치지 않고 직접 sudo
실행합니다 .echo
9189 execve("/bin/echo", ["echo", "line1\nline2\n"], ...
여기서는 문자 그대로 개행 문자를 받아 echo
인쇄 echo
합니다.
여기서 아이디어는 sudo
다음 사실을 수용하기 위해 이스케이프 쉘 레이어를 추가하는 것 입니다 sh -c
.하나의sudo
자체적으로 명령을 다른 매개변수로 사용하는 문자열입니다 .
다음 사례를 비교해 보세요.
sudo
공백을 피하십시오(이것은 명령 이름일 뿐이며 매개변수는 없습니다!).
$ sudo -i 'echo foo'
-bash: echo foo: command not found
sudo
백슬래시를 이스케이프 처리하면 실제로 작동합니다(Bash는 echo
백슬래시를 처리하지 않습니다).
$ sudo -i echo 'foo\bar'
foo\bar
탭과 동일:
$ sudo -i echo $'foo\tbar'
foo bar
여기에서는 백슬래시 주위에 추가 따옴표가 없으므로 Bash는 셸 명령줄을 처리할 때 이를 제거합니다( b
셸에 대한 특수 문자가 아니며 따옴표가 필요하지 않습니다. 이는 기본적으로 와 동일합니다 bash -c 'echo foo"b"ar'
).
$ bash -c 'echo foo\bar'
foobar
문제는 백슬래시를 사용하여 줄 바꿈을 이스케이프 처리할 수 없다는 점이며 sudo
이는 고려되지 않은 것 같습니다.
아무튼, 이런 문제는 필요한 명령어를 파일에 저장하고 스크립트로 실행해 보면 더 쉽게 참고할 수 있을 것 같습니다.
답변2
명령 구조를 변경할 수 있습니다.
echo "echo \"line1${n}line2${n}\"" | sudo -i bash -s
이렇게 하면 sudo
논쟁이 보이지 않으므로 문제를 일으키지 않습니다.