쓰기 권한이없는 파일로 stdout 리디렉션


113

파일에 대한 쓰기 권한이없는 파일을 수정하려고하면 오류가 발생합니다.

> touch /tmp/foo && sudo chown root /tmp/foo
> echo test > /tmp/foo
zsh: permission denied: /tmp/foo

Sudoing은 명령을 루트로 실행하기 때문에 도움이되지 않지만 쉘은 stdout 리디렉션을 처리하고 어쨌든 파일을 엽니 다.

> sudo echo test > /tmp/foo
zsh: permission denied: /tmp/foo

쉘을 루트로 열고 파일을 조작하는 것 외에도 stdout을 쓰기 권한이없는 파일로 리디렉션하는 쉬운 방법이 있습니까?

> sudo su
# echo test > /tmp/foo

2
StackOverflow의의에서 비슷한 질문에 대한 답변 stackoverflow.com/questions/82256/...
크리스티안 Ciupitu에게

tmp로 자신이 만든 파일에 대한 권한을 어떻게 가질 수 없습니까? 그것은 umask의 becuase입니까?
k961

@ k961 나는 chown소유자를 바꾸 곤했다 . 그것은 단지 예일뿐입니다
Michael Mrozek

답변:


116

예.를 사용 tee합니다. 그래서 echo test > /tmp/foo이된다

echo test | sudo tee /tmp/foo

( >>)를 추가 할 수도 있습니다

echo test | sudo tee -a /tmp/foo

27
Tee는 또한 stdout으로 출력됩니다. 때로는 내용물이 화면을 채우고 싶지 않습니다. 이 문제를 해결하려면echo test | sudo tee /tmp/foo > /dev/null
Shawn J. Goff

heredoc로 어떻게 하시겠습니까?
JohnDoea

26

파일 내용을 셸 리디렉션 연산자 echo와 같은 출력으로 >바꿉니다.

echo test | sudo dd of=/tmp/foo

Bourne 쉘 연산자 seek와 같이 잘리지 않고 파일에 쓰려면 (처음 에는 다른 오프셋으로 출력 하는 데 사용할 수 있음 1<>) :

echo test | sudo dd of=/tmp/foo conv=notrunc

>>GNU 를 사용하여 파일에 추가하려면 (예 :) dd:

echo test | sudo dd of=/tmp/foo oflag=append conv=notrunc

참조 GNU ddconv=excl(와 같은 기존 파일 건드리지 방지하기 위해 set -o noclobberPOSIX 쉘에서)을하고 conv=nocreat반대를위한 (만 기존 파일을 업데이트).


영리한! 이렇게 echo test | sudo tee /tmp/foo >/dev/null하면 출력을 폐기 해야 할 필요성이 줄어 듭니다 .
Adam Katz

2
나는 그것을 철회해야 할 수도 있습니다. 모호한 GNU 전용 옵션을 사용하지 않으면 이 답변의 우아함을 제거 하지 않는 한 dd신뢰할 수 없습니다iflag=fullblock oflag=fullblock . 을 고집하겠습니다 tee.
Adam Katz

5
dd는 모호하지 않은 bs = 1로 신뢰할 수 있음
umeboshi

2
@umeboshi 그러나 당신이하고있는 일을 정확히 알고있을만큼 경험이있는 경우에만 신뢰할 수 있습니다. 내용은 dd상당히 위험 할 수 있습니다 (그렇지 않으면 것은 대답 : 파괴) 만하면 약간의 실수가되었다. 따라서 새로운 사용자에게는 tee안전한 해안에있는 방법을 권장합니다 .
syntaxerror

1
@AdamKatz, dd of=file혼자 ( count/ skip... 없이 ) 경우 신뢰할 수 있습니다. iflag=fullblock여기서 dd입력에 읽은 내용을 출력에 쓰므로 필요하지 않습니다 . 전체 블록이 아니더라도 문제가되지 않습니다.
Stéphane Chazelas

12

tee 아마도 최선의 선택이지만 상황에 따라 다음과 같이 충분할 수 있습니다.

sudo sh -c 'echo test > /tmp/foo'

1
3 문제 : eval간단한 대신 sh -c; -i, 작업 디렉토리가 변경됩니다. 전체 명령을 루트로 실행하면 동작이 변경되거나 불필요한 위험이 발생할 수 있습니다. 왜 이것이 공감대를 얻었습니까?

4
당신은하지 않았지만 그것은 오해의 소지가 있으며 일반적으로 나쁘고 어쩌면 위험합니다.

5

나는 동의하지만, 그것은 sed (여기서는 GNU라고 가정 )가 작동 | sudo tee하는 정식 방법입니다 .sed

cat sudotest 
line 1

sudo sed -i '1iitest' sudotest && cat sudotest 
itest
line 1

sudo sed -i '$aatest' sudotest && cat sudotest 
itest
line 1
atest

-i파일을 제자리에 수정합니다. 1i의미 삽입 행 앞에 1. $a수단을 추가 할 마지막 행 다음에.

또는 xclipboard로 복사하십시오.

somecommand | xclip
sudo gedit sudotest
move cursor to desired place, click middle mouse button to insert, save

1
이것은 고대 중국 수수께끼와 같은 단어입니다. 이것이 얼마나 많은 공감대를 얻었는지 이해할 수 없습니다. ( hrmph )
syntaxerror

1
@syntaxerror : 죄송합니다. 저는 영어 원어민이 아닙니다. 명확하지 않은 것을 지정하면 답변을 개선 할 수 있습니다. Gert에 대한 65 개의 공감대와 비교할 때 4는 그렇게 많은 공감대가 아닌 것 같습니다.
사용자 알 수 없음

글쎄, 나는 4 :-D에 꽤 만족할 것이다. 당신의 영어는 전혀 나쁘지 않습니다. 그것은 일종의 간결한 기술자 대단한 말로 표현되었습니다. 네가 코더 인 것 같아 서로간에 코더는 그렇게 완벽하게 이해할 수 있지만, 비코 더는 말한 것처럼 ...
syntaxerror

참고 sed -i실제로 장소에서 파일을 수정하지 않습니다는 - 그것은 임시 파일을 생성하고 종료하기에 이름을 바꿉니다. 따라서 파이프 라인이 실행되는 동안 tail -f ...원본 파일과 같은 작업을 수행 하고 출력을 볼 수 없습니다.sed -i ...
Andrew Henle

@AndrewHenle : 그렇습니다. 크기가 커지거나 줄어들 수 있기 때문에 아마도 대부분의 sed 호출의 경우 일 것이므로 SSD의 동일한 위치에 쓸 수는 없습니다. . 영어를 모국어로 사용하지 않는 사람으로서 오해의 소지가없는 간단한 표현을 요청할 수 있습니까? 그냥 -i creates a new file of same name또는 뭔가 더 컴팩트 있는가? 나는 in place그것을 설명하기 때문에 내가 좋아하는 것 같아요 i. 는 GNU-나오지 맨 페이지를 호출 장소에 너무와 긴 플래그입니다 --in-place.
사용자가 알 수 없음

2

비슷한 문제에 대한 내 마음의 아이디어를 뒷받침하고 다음 해결책을 생각해 냈습니다.

  • sudo uncatuncat표준 입력을 읽고 명령 줄에 이름이 지정된 파일에 기록하는 프로그램은 어디에 있지만 uncat아직 작성 하지 않았습니다.

  • sudocatsudoedit내가 아직 작성하지 않은 변종은 클리너 sudo cat또는 sudo uncat.

  • 또는 sudoedit쉘 스크립트 인 EDITOR와 함께 사용 하는 이 작은 트릭

    #!/bin/sh
    # uncat
    cat > "$1"

    이는 중 하나로 호출 할 수 있습니다 |sudo ./uncat file또는 | EDITOR=./uncat sudoedit하지만 흥미로운 부작용이있다.


cat사기 파일 목록을 취 고양이 에 파일 목록이 소요되므로 uncat, inate을 취소 사기꾼 고양이 에 inate합니다. 각 파일에 얼마나 많이 넣을지 결정하려면 마술을 사용해야합니다. 대체 이름이 포함 dog, to-file, redirect.
ctrl-alt-delor

내가 uncat있을 때 내가 원하는 이유를 생각할 수 없습니다 tee.
와일드 카드

1
글쎄, teestdin을 stdout에 작성한다는 사소한 단점이 있습니다 /dev/null. stdout을로 리디렉션하여 사소하게 완화됩니다 . 다른 대안으로는 dd of=/tmp/foostderr에 상태 정보를 쓰는 (다른 답변에서 언급)과 cp /dev/stdin /tmp/foo.
Scott

1

moreutils 패키지의 스폰지를 사용하십시오. stdout에 쓰지 않는 이점이 있습니다.

echo test | sudo sponge /tmp/foo

파일을 겹쳐 쓰지 않고 추가하려면 -a 옵션을 사용하십시오.


1
나는 stdout에 글을 쓰지 않는 것이 어떤 이점이 있는지 잘 모르겠지만 /dev/null, 문제가 발생한 경우 출력을 리디렉션 할 수 있습니다.
Michael Mrozek

1
물론 / dev / null로 리디렉션 할 수 있지만 리디렉션없이 명령을 읽고 입력하기가 더 쉽습니다. stdout에 쓰지 않는 장점은 터미널이 쓰레기로 채워져 있지 않다는 것입니다.
Hontvári Levente

1
리디렉션을 절약하기 위해 패키지를 설치하지는 않지만 정기적으로 스폰지를 사용하므로 이미 있습니다.
Hontvári Levente

0

쉘이 수행하는 순서에서 오류가 발생합니다.

리디렉션은 셸이 실행되기 전에 처리 sudo되므로 현재 작업중인 사용자의 권한으로 수행됩니다. 리디렉션 대상을 만들거나자를 수있는 쓰기 권한이 없으므로 permission denied셸에서 오류가 발생합니다.

이 솔루션은 출력 파일이 제공 한 ID로 생성되는 것을 보장하는 것입니다 sudo함께 예 tee:

$ generate_output | sudo tee target_file
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.