명령 대체: /dev/stdin: 권한이 거부되었습니다.

명령 대체: /dev/stdin: 권한이 거부되었습니다.

전체 표준 입력을 변수로 읽고 싶습니다. 나는 새로운 프로세스를 생성하고 싶지 않습니다.

Bash 매뉴얼에서:

명령 대체를 사용하면 $(cat file)명령을 동일하지만 더 빠른 명령으로 바꿀 수 있습니다 $(< file).

기본적으로 작동하지만 /proc/fd문제는 다음과 같이 쉽게 깨집니다 sudo.

# same user. works
[root@okdistr ~]# echo aaa | bash -c 'echo $(</dev/stdin)'
aaa

# different user. fail
[root@okdistr ~]# echo aaa | sudo -u nobody bash -c 'echo $(</dev/stdin)'
bash: /dev/stdin: Permission denied

# spawn new process. not want
[root@okdistr ~]# echo aaa | sudo -u nobody bash -c 'echo $(cat)'
aaa

# try to read from fd: silently fails
[root@okdistr ~]# echo aaa | sudo -u nobody bash -c 'echo $(<&0)'

# works, but too complex
[root@okdistr ~]# echo aaa | sudo -u nobody bash -c 'a=; while true; do rc=0; read -N1024 b || rc=$?; a=$a$b; [ $rc = 0 ] || break; done; echo "$a"'
aaa

[root@okdistr ~]#

왜 실패했나요 $(<&0)?

답변1

먼저 제가 제안하는 해결책은 다음과 같습니다. 그런 다음 관찰한 두 가지 오류에 대해 논의합니다.

제안된 솔루션

Bash 변수는 NUL 문자를 포함할 수 없습니다. 따라서 파일에 해당 문자가 포함되어 있지 않은 경우에만 전체 파일을 bash 변수로 읽을 수 있습니다. 이 bash 제한 사항에 따라 다음이 적합합니다.

$ echo aaa | { read -rd "" v; echo "$v"; }
aaa

를 사용하면 read -d '' varbash는 NUL 문자가 발견될 때까지 표준 입력을 읽습니다. bash 변수는 어쨌든 NUL 문자를 포함할 수 없으므로 이 접근 방식은 bash의 고유한 한계 이상으로 사용자를 제한하지 않습니다.

bash가 백슬래시 시퀀스를 해석하지 못하도록 하는 옵션입니다 -r. read또한 선행 및 후행 공백을 유지하려면 명령문 앞에 공백을 추가 IFS=하세요 read.

"fd에서 읽으려는 시도: 자동으로 실패했습니다."

# echo aaa | sudo -u nobody bash -c 'echo $(<&0)'
#

위의 자동 실패는 sudo 없이도 발생합니다.

$ echo aaa | bash -c 'echo $(<&0)'
$

서브쉘을 생성하지 않아도 이런 일이 발생합니다.

$ echo aaa | echo $(<&0)
$

문제는 이것이 &0유효한 파일 이름이 아니라는 것입니다. 관찰하다:

$ echo aaa | cat &0
[1] 22635
bash: 0: command not found

Bash에서는 and 또는 &0<결합할 때만 의미가 있습니다 >.

bash 문서를 다시 살펴보겠습니다.

명령 대체 $(cat file)은 동일하지만 더 빠른 $(< file)로 대체될 수 있습니다.

cat &0작동하지 않기 때문에 $(< &0)기대해서는 안됩니다.

"다른 사용자입니다. 실패했습니다."

이것은 합리적인 일인 것 같습니다.

# echo aaa | sudo -u nobody bash -c 'echo $(cat /dev/stdin)'
cat: /dev/stdin: Permission denied

실패 이유를 이해하기 위해 다음 권한을 확인해 보겠습니다 /dev/stdin.

# echo aaa | sudo -u nobody bash -c 'ls -lH /dev/stdin'
prw------- 1 root root 0 Jul  1 15:42 /dev/stdin

사용자에게 파일에 액세스할 수 있는 권한이 없습니다. 이것은 의미가 있습니다: 누군가가 루트의 파일을 망쳐놓는 것을 원하지 않습니다.

'더 똑똑한' 운영 체제는 누구도 액세스할 수 없다는 사실을 알 수 있습니다./dev/stdin 이 특별한 경우에는그러나 보안을 위해서는 운영 체제가 스스로를 능가하려고 시도하지 않는 것이 가장 좋습니다.

답변2

이 작업을 수행하려면 이러한 링크가 필요하지 않습니다 /dev. 환경 변수가 지워졌다는 것을 알고 있지만 sudo어쨌든 다른 쉘을 호출하므로 변수를 인수로 전달할 수 있습니다.

sudo -u nobody bash -c '
    a=$1; echo "$a"
' -- "$(echo aaa)"

...또는...

echo aaa | { 
    sudo -u nobody bash -c '
        a=$1; echo "$a"
    ' -- "$(</dev/fd/0)"
}

이 두 개는 다음과 같이 인쇄됩니다.

aaa

...표준 출력으로...

관련 정보