vim "sudo로 쓰기"트릭은 어떻게 작동합니까?


1410

많은 사람들이 sudo로 vim을 여는 것을 잊어 버린 경우에도 루트 권한이 필요한 파일에 쓸 수있는 명령을 보았을 것입니다.

:w !sudo tee %

문제는 내가 여기서 정확히 일어나고있는 것을 얻지 못한다는 것입니다.

나는 이미 이것을 알아 냈습니다 : w이것은

                                                        *:w_c* *:write_c*
:[range]w[rite] [++opt] !{cmd}
                        Execute {cmd} with [range] lines as standard input
                        (note the space in front of the '!').  {cmd} is
                        executed like with ":!{cmd}", any '!' is replaced with
                        the previous command |:!|.

모든 라인을 표준 입력으로 전달합니다.

!sudo tee부분은 호출 tee관리자 권한으로.

모두 이해하기 %위해서는 파일 이름을에 대한 매개 변수로 출력해야 tee하지만이 동작에 대한 도움말에서 참조를 찾을 수 없습니다.

tl; dr 누군가 내가이 명령을 분석하도록 도와 줄 수 있습니까?


5
@Nathan : :w !sudo cat > %잘 작동하지 않고 표준 출력을 오염시키지 않습니까?
Bjarke Freund-Hansen

51
@bjarkef-아니요, 작동하지 않습니다. 이 경우에 sudo적용 cat되지만에 적용 >되지 않으므로 허용되지 않습니다. sudo 서브 쉘에서 전체 명령을 실행할 수는 :w !sudo sh -c "cat % > yams.txt"있지만 서브 쉘에서는 %nil 이기 때문에 작동하지 않습니다 . 파일 내용을 비 웁니다.
Nathan Long

3
해당 명령을 입력 한 후 경고 메시지가 나타날 수 있음을 추가하고 싶습니다. 그렇다면 L을 누르십시오. 그러면 enter를 누르라는 메시지가 표시됩니다. 그러면 파일이 저장됩니다.
pablofiumara

9
@NathanLong @knittl : Vim 이 서브 쉘에 도달하기 전에 파일 이름을 대체하기 때문에 :w !sudo sh -c "cat >%"실제로 작동합니다 . 그러나 파일 이름에 공백이 있으면 둘 다 작동하지 않습니다. 그렇게 하거나 고쳐야합니다. sudo tee %%:w !sudo sh -c "cat >'%'":w !sudo tee "%"
한 서울 –

1
: W를 사용하여 저장하고 파일을 다시로드하십시오. command W : execute ': silent w! sudo tee %> / dev / null'| :편집하다!
디에고 로베르토 도스 산토스

답변:


1610

에서 :w !sudo tee %...

% "현재 파일"을 의미

으로 유진 y를 지적 , %참에 전달 "현재 파일 이름", 의미 하는가 tee가 덮어 쓰기 할 파일을 알 수 있도록합니다.

(대체 명령에서, 그것은 약간 다르다;로 :help :%쇼, 그건 equal to 1,$ (the entire file)이) 파일 이름으로 평가하지 않는 것을 지적 @Orafu에 (덕분에 예를 들어,. :%s/foo/bar수단 " 현재 파일 의 발생을 대체 foo와 함께 bar."당신이 강조하는 경우 을 입력하기 전에 일부 텍스트 :s를 사용하면 강조 표시된 줄이 %대체 범위로 대체됩니다.)

:w 파일을 업데이트하지 않습니다

이 트릭의 혼란스러운 부분 중 하나 :w는 파일을 수정 한다고 생각할 수 있지만 그렇지 않습니다. 열고 수정 file1.txt한 다음 실행 :w file2.txt한 경우 "다른 이름으로 저장"이됩니다. file1.txt수정되지는 않지만 현재 버퍼 내용이로 전송됩니다 file2.txt.

대신 쉘 명령을 사용하여 버퍼 내용을 수신file2.txt 할 수 있습니다 . 예를 들어 내용 만 표시합니다.:w !cat

Vim이 sudo 액세스로 실행되지 않은 경우 :w보호 된 파일을 수정할 수 없지만 버퍼 내용을 셸에 전달하면 셸 의 명령 을 sudo로 실행할 있습니다 . 이 경우에는를 사용 tee합니다.

티 이해

관해서 tee, 화상 tee통상 배시 배관 상황에서 T 자관과 같은 명령을 : 그것은 지정된 파일 (들)에 출력을 지시하고 또한 표준 출력에 보낼 다음 파이프 명령에 의해 포착 될 수있다.

예를 들어에서에서 ps -ax | tee processes.txt | grep 'foo'프로세스 목록은 텍스트 파일에 기록 되고에 전달됩니다 grep.

     +-----------+    tee     +------------+
     |           |  --------  |            |
     | ps -ax    |  --------  | grep 'foo' |
     |           |     ||     |            |
     +-----------+     ||     +------------+
                       ||   
               +---------------+
               |               |
               | processes.txt |
               |               |
               +---------------+

( Asciiflow로 만든 다이어그램 )

자세한 내용은 tee매뉴얼 페이지 를 참조하십시오.

해킹으로 티

귀하의 질문에 설명 된 상황에서 사용 tee하는 것은 우리가하는 일의 절반을 무시하기 때문에 해킹 입니다. sudo tee파일에 쓰고 버퍼 내용을 표준 출력으로 보내지 만 표준 출력은 무시합니다 . 이 경우 다른 파이프 명령에 아무것도 전달할 필요가 없습니다. 우리는 tee파일을 작성하는 다른 방법으로 사용 하고 있으며로 호출 할 수 있습니다 sudo.

이 트릭을 쉽게 만들기

이것을 .vimrc사용 하여이 트릭을 사용하기 쉽게 만들 수 있습니다 : 그냥 type :w!!.

" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! w !sudo tee > /dev/null %

> /dev/null부분은 명시 적으로 내가 말했듯이, 우리가 다른 파이프 명령에 아무것도 통과 할 필요가 없습니다, 때문에, 표준 출력을 버린다.


147
특히 당신의 표기법 "w !!" "sudo !!"를 사용한 후 기억하기 쉬운 명령 행에서.
아이 단 케인

11
따라서 이것은 teestdin을 파일에 쓰는 기능을 사용 합니다. 나는 그 일을하는 일을하는 프로그램이 없다는 것에 놀랐습니다 (내가 들어 본 적이없는 프로그램을 찾았습니다 sponge). 일반적인 "파일에 스트림 쓰기"는 쉘 내장에 의해 수행되는 것 같습니다. Vim !{cmd}은 쉘을 포크 cmd하지 않습니까 (포크 대신)? 아마도 더 분명한 것 sh -c ">"보다는 오히려 작동하는 변형을 사용하는 것일 수 있습니다 tee.
Steven Lu

2
@Steven Lu : 데비안 기반 배포판을 제외한 거의 모든 배포판 sponge에서 moreutils패키지의 일부입니다 . moreutils같은 일반적인 도구로 파에있는 꽤 좋은 도구가 xargstee.
스위스

10
이 별칭을 확장하여 vim에게 변경된 파일 내용을 현재 버퍼에 자동으로로드하도록 지시하는 방법은 무엇입니까? 자동화 방법은 무엇입니까?
Zlatko

10
@ user247077 :이 경우 cat루트로 실행되고 출력은 루트로 실행되지 않는 쉘에 의해 리디렉션됩니다. 와 동일합니다 echo hi > /read/only/file.
WhyNotHugo

99

실행 된 명령 행 %에서 현재 파일 이름을 나타냅니다 . 이 내용은 다음과 :help cmdline-special같습니다.

In Ex commands, at places where a file name can be used, the following
characters have a special meaning.
        %       Is replaced with the current file name.

이미 알았 듯이 :w !cmd현재 버퍼의 내용을 다른 명령으로 파이프합니다. 어떤 tee일은 표준 출력에 하나 개 이상의 파일을 표준 입력을 복사합니다. 따라서 root 인 동안:w !sudo tee % > /dev/null 현재 버퍼의 내용을 현재 파일에 효과적으로 씁니다 . 이를 위해 사용할 수있는 다른 명령은 다음과 같습니다.dd

:w !sudo dd of=% > /dev/null

바로 가기로이 매핑을 다음에 추가 할 수 있습니다 .vimrc.

" Force saving files that require root permission 
cnoremap w!! w !sudo tee > /dev/null %

위와 같이 입력 :w!!<Enter>하면 파일을 루트로 저장할 수 있습니다 .


1
흥미롭고 :help _%입력 한 내용을 표시하지만 :help %중괄호 일치 키를 표시합니다. 나는 밑줄 접두어를 시도하려고 생각하지 않았을 것입니다. vim 문서에서 어떤 종류의 패턴입니까? 도움을 찾을 때 시도해야 할 다른 '특별한'사항이 있습니까?
David Pope

2
@David : help명령이 태그로 이동합니다. 에서 사용 가능한 태그를 볼 수 있습니다 :h help-tags. 명령 줄 완성을 사용하여 일치하는 태그를 볼 수도 있습니다 :h cmdline<Ctrl-D>(또는 적절하게 :h cmdline<Tab>설정 한 경우 wildmode)
Eugene Yarmash

1
cmap w!! w !sudo tee % > /dev/null이 작업을 수행하려면 .vimrc 파일에서 사용해야 했습니다. %위의 답변 에서 잘못 배치 되었습니까? (여기서 vim 전문가는 없습니다.)
dmmfll

@DMfll 그렇습니다. 대답의 명령은 sudo tee > /dev/null /path/to/current/file실제로 의미가 없습니다. (편집
예정

1
@ jazzpi : 당신이 틀렸다. 셸은 실제로 명령 줄에서 파일 리디렉션을 수행하는 위치를 신경 쓰지 않습니다.
유진 야마 쉬

19

이것은 또한 잘 작동합니다 :

:w !sudo sh -c "cat > %"

이것은 @Nathan Long의 의견에서 영감을 얻었습니다.

공지 사항 :

"쉘로 전달하기 전에 확장 '되기를 원 %하기 때문에 대신 사용해야합니다 .


11
이것은 효과가 있지만 여러 프로그램 (sh 및 cat)에 대한 sudo 액세스를 제공합니다. 다른 예는 PATH 수정 공격을 방지하기 위해을 대체 tee하여 더 안전 할 수 있습니다 /usr/bin/tee.
idbrii

18

:w -파일을 작성하십시오.

!sudo -쉘 sudo 명령을 호출하십시오.

tee-tee를 사용하여 재 지정된 쓰기 (vim : w) 명령의 출력. %는 현재 파일 이름, 즉 /etc/apache2/conf.d/mediawiki.conf입니다. 즉, tee 명령은 루트로 실행되며 표준 입력을 사용하여 %로 표시되는 파일에 씁니다. 그러나 파일을 다시로드하라는 메시지가 표시됩니다 (vim 자체에 변경 사항을로드하려면 L을 누르십시오).

튜토리얼 링크


9

허용 된 답변은 모든 것을 다루므로 레코드에 사용 하는 바로 가기 의 또 다른 예를 제공 합니다.

etc/vim/vimrc(또는 ~/.vimrc)에 추가하십시오 .

  • cnoremap w!! execute 'silent! write !sudo tee % >/dev/null' <bar> edit!

어디:

  • cnoremap: vim 에게 명령 줄에 다음 단축키가 연결되어 있음을 알려줍니다 .
  • w!!: 바로 가기 자체.
  • execute '...': 다음 문자열을 실행하는 명령입니다.
  • silent!: 조용히 실행
  • write !sudo tee % >/dev/null: OP 질문, NULL깨끗한 명령을 내리기 위해 메시지 리디렉션을 추가했습니다.
  • <bar> edit!:이 트릭은 케이크의 버찌입니다. 또한 edit버퍼를 다시로드 하고 버퍼가 변경되는 것과 같은 메시지를 피하는 명령을 호출합니다 . 파이프 기호 <bar>를 작성하여 두 명령을 분리 하는 방법 입니다.

도움이 되길 바랍니다. 다른 문제도 참조하십시오 :


조용한! 암호 프롬프트를 표시하지 않아서 보이지 않음
Andy Ray

7

" sudo파일을 여는 동안 쓰기 를 잊어 버린 Oups " 문제 에 대한 또 다른 접근 방식을 제안하고 싶습니다 .

을 수신하고 permission denied입력 하는 대신 파일 소유자가 :w!!조건부 vim명령을 수행 하는 것이 더 우아하다는 것을 알았습니다 .sudo vimroot

이것은 구현하기 쉽습니다 (더 우아한 구현이있을 수 있습니다. 나는 분명히 bash-guru가 아닙니다).

function vim(){
  OWNER=$(stat -c '%U' $1)
  if [[ "$OWNER" == "root" ]]; then
    sudo /usr/bin/vim $*;
  else
    /usr/bin/vim $*;
  fi
}

그리고 그것은 정말 잘 작동합니다.

이것은 하나보다 더 bash중심적인 접근 방식 vim이므로 모든 사람이 좋아할 수는 없습니다.

물론이야:

  • 실패 할 유스 케이스가 있습니다 (파일 소유자가 root아니지만 필요 sudo하지만 함수를 편집 할 수있는 경우)
  • vim파일을 읽기 전용으로 사용할 때는 의미가 없습니다 (관심있는 한, 사용 tail하거나 cat작은 파일)

그러나 이것은 훨씬 더 나은 개발 사용자 경험을 가져다 주며 , 이는 IMHO를 사용할 때 잊어 버리는 경향이 있습니다 bash. :-)


5
이것은 훨씬 덜 용서한다는 것을 명심하십시오. 개인적으로, 대부분의 실수는 바보 같은 실수입니다. 그래서 나는 어리 석고 결과적인 일을 할 때 머리를 쓰는 것을 선호합니다. 이것은 물론 선호의 문제이지만, 특권 확대는 양심적 인 행동으로 여겨졌습니다. 또한 : ": w !!"를 만들기 위해 이것을 자주 경험한다면 자동 sudo를 자동으로 처리하기에 충분한 귀찮음 (그러나 owner = root 인 경우에만); 현재 워크 플로를 검사 할 수 있습니다.
Payne

흥미로운 의견이지만 root, 암호를 쿼리 할 때 파일을 열 때 의식이 있어야합니다 .
Augustin Riedinger

아! 차이점이 있습니다. sudo 사용자의 "NOPASSWD"설정 여부에 따라 다릅니다.
Payne

그런 다음 NOPASSWD를 갖는 것은 덜 용서하는 것입니다 ... :)
Augustin Riedinger

4

네오 빔

대화 형 호출 ( https://github.com/neovim/neovim/issues/1716 )의 문제로 인해 Beco 박사의 답변에 따라 네오 빔에 이것을 사용하고 있습니다.

cnoremap w!! execute 'silent! write !SUDO_ASKPASS=`which ssh-askpass` sudo tee % >/dev/null' <bar> edit!

ssh-askpasssudo 암호 를 묻는 대화 상자가 열립니다 .

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