sudo cat이 Permission denied를 제공하지만 sudo vim이 잘 작동하는 이유는 무엇입니까?


87

아치의 pacman.conf 파일에 저장소 소스 추가를 자동화하려고하지만 echo쉘 스크립트에서 명령을 사용합니다 . 그러나 다음과 같이 실패합니다.

sudo echo "[archlinuxfr]" >> /etc/pacman.conf
sudo echo "Server = http://repo.archlinux.fr/\$arch" >> /etc/pacman.conf
sudo echo " " >> /etc/pacman.conf

-bash: /etc/pacman.conf: Permission denied

vim을 사용하여 수동으로 /etc/pacman.conf를 변경하면

sudo vim /etc/pacman.conf

으로 vim을 종료 :wq하면 모든 것이 잘 작동하며 내 pacman.conf는 "Permission denied"불만없이 수동으로 업데이트되었습니다.

왜 그렇습니까? 그리고 어떻게 sudo echo일할 수 있습니까? (btw, 나도 사용해 보았지만 sudo cat권한이 거부되어 실패했습니다)


답변:


52

문제는 리디렉션이에서가 아니라 원래 셸에서 처리되고 있다는 것 sudo입니다. Shells는 마음을 읽을 수 없으며 그 특정 >>이 자신을 sudo위한 것이 아니라위한 것인지를 알지 못합니다.

다음을 수행해야합니다.

  1. 리디렉션을 인용하십시오 (그래서 전달됩니다 sudo)
  2. 사용 sudo -s(즉, 그래서 sudo인용 리디렉션을 처리하는 쉘을 사용합니다.)

1
따라서 다음과 같이 두 단계로 수행합니다. (1) sudo -s(2) echo "# test">> /etc/pacman.conf 작동합니다. 그러나 이것을 한 줄로 실행할 수 있습니까?
Calvin Cheng

15
sudo -s 'echo "# test" >>/etc/pacman.conf'내가 당신에게 전달하려고했던 것입니다.
geekosaur 2012

2
실제로 위의 답변을 읽은 후 시도했지만 다음과 같은 이상한 오류가 발생했습니다 .- sudo -s 'echo "# test" >> /etc/pacman.conf' /bin/bash: echo "# test" >> /etc/pacman.conf: No such file or directory그래서 나중에 2 단계 수동 프로세스를 시도했습니다.
캘빈 쳉

16
아 ..... 이런 식으로 마지막 시도 일 -echo 'echo "# test" >> /etc/pacman.conf' | sudo -s
캘빈 쳉

1
sudo구성 비활성화 에 대해 어떻게 / 어디에서 찾을 수 -s있습니까? visudo?
캘빈 쳉

129

@geekosaur가 설명했듯이 셸은 명령을 실행하기 전에 리디렉션을 수행합니다. 이것을 입력 할 때 :

sudo foo >/some/file

현재 쉘 프로세스는 /some/file쓰기를 위해 먼저 열려고 시도하는 자체 복사본을 만들고 성공하면 해당 파일 설명자를 표준 출력으로 만들고 성공한 경우에만 실행 sudo합니다. 이것은 첫 번째 단계에서 실패합니다.

허용되는 경우 (sudoer 구성은 종종 실행중인 셸을 배제 함) 다음과 같이 할 수 있습니다.

sudo bash -c 'foo >/some/file'

그러나 일반적으로 좋은 해결책은 | sudo tee대신 >| sudo tee -a대신 사용 하는 것입니다 >>. 리디렉션이 sudo처음에 필요한 유일한 이유 인 경우 특히 유용합니다 . 결국 불필요하게 루트로 프로세스를 실행하는 sudo것은 피하기 위해 만들어진 것입니다. 그리고 echo루트로 실행 하는 것은 어리석은 일입니다.

echo '[archlinuxfr]' | sudo tee -a /etc/pacman.conf >/dev/null
echo 'Server = http://repo.archlinux.fr/$arch' | sudo tee -a /etc/pacman.conf >/dev/null
echo ' ' | sudo tee -a /etc/pacman.conf >/dev/null

이름이 지정된 파일 자체 표준 출력 모두에 출력을 보내기 > /dev/null때문에 마지막에 추가 했으며 터미널에서 볼 필요가 없습니다. 합니다 ( 명령은. 그것의 이름을 가져옵니다 곳이다, 물리적 파이프 라인에서 "T"커넥터와 같은 역할) 그리고 (작은 따옴표로 전환 ... (대신 두 배의) ... 모든 것이 문자 그대로 내가 그래서) 의 앞에 백 슬래시를 넣어하지 않았다 에서 . (따옴표 또는 백 슬래시가 없으면 셸 매개 변수 값으로 대체됩니다. 아마도 존재하지 않을 것입니다.이 경우는 아무 것도 대체되지 않고 사라집니다.)teetee''""$$arch$archarch$arch

따라서 .NET을 사용하여 루트로 파일에 쓰는 작업을 처리합니다 sudo. 이제 쉘 스크립트에서 줄 바꿈이 포함 된 텍스트를 출력하는 방법에 대한 긴 여담을 살펴 보겠습니다. :)

BLUF를 위해 내가 선호하는 솔루션은 위의 sudo tee명령에 here-document를 입력하는 것입니다 . 다음 필요가 없다 cat거나 echo또는 printf전혀 다른 명령 또는. 작은 따옴표는 센티넬 소개로 이동 <<'EOF'했지만 동일한 효과가 있습니다. 본문은 리터럴 텍스트로 처리되므로 그대로 $arch둡니다.

sudo tee -a /etc/pacman.conf >/dev/null <<'EOF'
[archlinuxfr]
Server = http://repo.archlinux.fr/$arch

EOF

하지만 그렇게했지만 대안이 있습니다. 다음은 몇 가지입니다.

echo줄에 하나씩 붙일 수 있지만 모두 하위 셸로 그룹화하므로 한 번만 파일에 추가하면됩니다.

(echo '[archlinuxfr]'
 echo 'Server = http://repo.archlinux.fr/$arch'
 echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null

에 추가 -e하는 경우 echo(그리고 POSIX가 아닌 확장을 지원하는 셸을 사용하고있는 경우) 다음을 사용하여 줄 바꿈을 문자열에 직접 포함 할 수 있습니다 \n.

# NON-POSIX - NOT RECOMMENDED
echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | 
  sudo tee -a /etc/pacman.conf >/dev/null

그러나 위에서 말했듯이 POSIX에서 지정한 동작이 아닙니다. 셸은 리터럴 -e뒤에 리터럴 \ns 무리가있는 문자열을 에코 할 수 있습니다 . 이를 수행하는 POSIX 방식은 printf대신 사용하는 것입니다 echo. 인수를 자동으로 처리 echo -e하지만 끝에 자동으로 줄 바꿈을 추가하지 않으므로 추가로 추가해야합니다 \n.

printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n \n' | 
  sudo tee -a /etc/pacman.conf >/dev/null

두 솔루션 중 하나를 사용하여 명령이 인수 문자열로 가져 오는 것은 두 문자 시퀀스 \n를 포함하며이를 개행 문자로 변환하는 것은 명령 프로그램 자체 ( printf또는 내부 코드 echo)에 달려 있습니다. 많은 최신 셸에서 ANSI 따옴표 $'... 를 사용하는 옵션이 있습니다.이 옵션은 명령 프로그램이 문자열을보기 전에 리터럴 줄 바꿈 으로 '같은 시퀀스를 변환 합니다. 즉, 이러한 문자열은 일반 old -less를 포함하여 모든 명령과 함께 작동합니다 .\n-eecho

echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | 
  sudo tee -a /etc/pacman.conf >/dev/null

그러나 echo -eANSI 따옴표 보다 이식성이 높지만 여전히 POSIX가 아닌 확장입니다.

그리고 이것들이 모두 옵션이지만 tee <<EOF위 의 직접적인 솔루션을 선호합니다 .


흥미 롭군요! / dev / null에 파일을 청킹하는 이유를 설명하는 메모를 추가 할 수 있습니까?
knite

sudo bash -c 'foo >/some/file'osx에서 나를 위해 작동합니다 :-)
kayochin

여러 줄 텍스트로 작동하기 때문에이 답변을 선호합니다. cat <<EOF | sudo tee -a /some/file > /dev/null ...
ltvan

외부 cat프로세스를 추가 한 것을 제외하고는 사실상 저의 마지막 대답 입니다. :)
Mark Reed

17

http://www.innovationsts.com/blog/?p=2758

위의 지침이 명확하지 않기 때문에 해당 블로그 게시물의 지침을 사용하고 있습니다. 예제를 통해 수행해야하는 작업을 더 쉽게 확인할 수 있습니다.

$ sudo 고양이 /root/example.txt | gzip> /root/example.gz
-bash : /root/example.gz : 권한이 거부되었습니다.

오류를 일으키는 것은 파이프 라인에서 두 번째 명령 (gzip 명령)입니다. 그것이 -c 옵션과 함께 bash를 사용하는 우리의 기술이 들어오는 곳입니다.

$ sudo bash -c 'cat /root/example.txt | gzip> /root/example.gz '
$ sudo ls /root/example.gz
/root/example.gz

ls 명령의 출력에서 ​​압축 파일 생성이 성공했음을 알 수 있습니다.

두 번째 방법은 명령 문자열을 bash에 전달한다는 점에서 첫 번째 방법과 유사하지만 sudo를 통해 파이프 라인에서 수행합니다.

$ sudo rm /root/example.gz
$ echo "cat /root/example.txt | gzip> /root/example.gz"| sudo bash
$ sudo ls /root/example.gz
/root/example.gz


1
이러한 간단한 명령의 경우 bash 대신 sh를 사용하는 것이 약간 더 나을 수 있습니다. 예 : sudo sh -c 'cat /root/example.txt | gzip> /root/example.gz '. 그러나 그렇지 않으면 좋은 설명, +1.
브라이스


1

1 단계 bash 파일 ( write_pacman.sh)에 함수 생성

#!/bin/bash

function write_pacman {
 tee -a /etc/pacman.conf > /dev/null << 'EOF'
  [archlinuxfr]
  Server = http://repo.archlinux.fr/\$arch
EOF
}

'EOF'$arch변수를 해석하지 않습니다 .

STE2 소스 bash 파일

$ source write_pacman.sh

STEP 3 기능 실행

$ write_pacman

EOF에 대한 견적은 무엇입니까?
bilabila

0

추가 파일 (sudo cat) :

cat <origin-file> | sudo tee -a <target-file>

파일에 에코 추가 (sudo echo) :

echo <origin> | sudo tee -a <target-file>

(추가) 출력 무시 :

echo >origin> | sudo tee -a <target-file> >/dev/null
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.