전체 표준 입력을 변수로 읽고 싶습니다. 나는 새로운 프로세스를 생성하고 싶지 않습니다.
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 '' var
bash는 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
...표준 출력으로...