`commands`
(더 이상 사용되지 않는) 백틱을 사용하여 (명령줄에서) 루트 권한으로 중첩이 수행 되지만 sudo
명령 대체는 $(...)
수행되지 않습니까?
예를 들어
sudo mount `blkid -u /dev/sda1` ...
sudo mount `sudo blkid -u /dev/sda1` ...
그리고
sudo mount $(blkid -u /dev/sda1) ...
sudo mount $(sudo blkid -u /dev/sda1) ...
방법에 차이가 있나요? 네 줄 중 어느 줄이 올바른 사용법인지조차 확신할 수 없습니다( sudo
blkid가 아니라 의사 코드일 뿐입니다). 아니면 쉘에 의존합니까?
답변1
`...`
$(...)
동일하지만 구문이 다르기 때문에 하나는 Bourne 셸에서, 다른 하나는 Korn 셸에서 옵니다. 전자는 더 이상 사용되지 않지만 고대 Bourne 셸과의 하위 호환성을 위해 Bourne 유사 셸에서 여전히 지원됩니다 .
다른 쉘에는 다른 구문이 있습니다. 예를 들어 fish
has (...)
및 rc
/ es
have `cmd
또는 `{more complex cmd}
은 `(sep){cmd}
다른 분할 동작을 지정합니다. ksh93
그리고 (하위 쉘이 없는) 변형 mksh
도 있습니다 .${ ...; }
어쨌든 이는 쉘 언어의 구문이므로 이를 해석하고 명령 대체를 수행하려면 쉘이 필요합니다.
존재하다:
sudo cmd1 `cmd2`
Bourne과 같은 껍질에서는 껍질이
cmd2
출력이 파이프로 리디렉션되는 하위 프로세스에서 실행됩니다.- 파이프의 다른 쪽 끝에서 이 cmd의 출력을 읽습니다.
- 후행 줄 바꿈을 제거하고,
- 세분화 결과에 따르면
$IFS
- 생성된 단어에 대해 파일 이름 생성을 수행합니다(in 외에도
zsh
일부 ksh 변형은 중괄호 확장도 수행함). - 그런 다음 결과 단어는
sudo
다른 하위 프로세스에서 실행되는 명령에 별도의 인수로 전달됩니다.
sudo
그런 다음 uid를 변경하고 인수로 전달된 명령을 실행하십시오.
다른 uid로 실행 하려면 명령 대체를 수행하는 쉘 코드를 해석하기 위해 실행 중인 쉘이 cmd2
필요합니다 .sudo
sudo sh -c 'cmd1 $(cmd2)'
sudo fish -c 'cmd1 (cmd2)'
sudo rc -c 'cmd1 `cmd2'
등.
Bourne과 유사한 쉘에서는 명령 대체가 여전히 큰따옴표 내에서 수행되므로아니요하다:
sudo sh -c "cmd1 $(cmd2)"
cmd2
첫째, 로 실행되지 않으며 root
출력 cmd2
(이번에는 따옴표 안에 있기 때문에 분할+glob의 영향을 받지 않음)이 sh
코드로 해석되므로 일반적으로 명령 주입 취약점을 구성합니다. 예를 들어, 출력인 경우 호출자 cmd2
에게 설명 하고 다시 시작하라는 메시지가 표시됩니다 .$(reboot)
sh
sudo
cmd1 $(reboot)
마찬가지로 변수의 내용을 전달하려면 다음을 수행하지 마세요.sudo sh -c 'cmd1 $(cmd2) '"$var"
당신의셸( 로 시작한 셸 제외 sudo sh -c 'cmd1 $(cmd2 '"$var"')'
sudo
) 을 cmd1
또는 로 변경합니다 cmd2
. 대신 이러한 변수의 내용을 추가로 전달하세요.논쟁도착 sh
(거기 아님)암호sudo
매개변수) 또는 환경 변수를 통해(따라서 실행된 셸의 변수이기도 함):
sudo sh -c 'cmd1 $(cmd2) "$1"' sh "$var"
sudo VAR="$var" sh -c 'cmd1 $(cmd2) "$VAR"'
sudo sh -c 'cmd1 $(cmd2 "$1")' sh "$var"
sudo VAR="$var" sh -c 'cmd1 $(cmd2 "$VAR")'
여기에서 언제든지 다음 작업을 수행할 수도 있습니다.
sudo cmd1 $(sudo cmd2) "$var"
sudo cmd1 $(sudo cmd2 "$var")
즉,당신의셸은 이 두 명령을 별도의 두 호출로 실행하므로 sudo
둘 다 높은 권한으로 실행될 수 있습니다.
위에서 언급했듯이 Bourne과 같은 쉘(그러나 이는 다르지만 csh와 같은 쉘에도 적용됨)에서 인용되지 않은 명령 대체는 분할+glob에 의해 제어되므로 분리된 목록을 출력할 때 와일드카드 패턴이 가능한 경우에만 $(cmd2)
사용해야 합니다. 인용없이. 출력(후행 개행 없이)을 전체적으로 전달하려는 경우cmd1 $(cmd2)
cmd2
$IFS
cmd2
하나cmd1
원하는 매개변수를 선택 cmd1 "$(cmd2)"
하거나 cmd1 -- "$(cmd2)"
매개변수가 옵션으로 처리되지 않도록 해야 합니다(옵션 닫는 태그가 지원된다고 가정 cmd1
) --
.
따라서 특정 사용 사례의 경우 다음과 같습니다.
sudo DEVICE="$device" sh -c 'mount -- "$(blkid -u -- "$DEVICE")"'
mount
아니면 그냥 성공을 요청하세요 blkid
:
sudo DEVICE="$device" sh -c '
output=$(blkid -u -- "$DEVICE") &&
mount -- "$output"
'