[vim] vim “sudo로 쓰기”트릭은 어떻게 작동합니까?

많은 사람들이 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 누군가 내가이 명령을 분석하도록 도와 줄 수 있습니까?



답변

에서 :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부분은 명시 적으로 내가 말했듯이, 우리가 다른 파이프 명령에 아무것도 통과 할 필요가 없습니다, 때문에, 표준 출력을 버린다.


답변

실행 된 명령 행 %에서 현재 파일 이름을 나타냅니다 . 이 내용은 다음과 :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>하면 파일을 루트로 저장할 수 있습니다 .


답변

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

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

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

공지 사항 :

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


답변

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

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

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

튜토리얼 링크


답변

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

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>를 작성하여 두 명령을 분리 하는 방법 입니다.

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


답변

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. 🙂


답변

네오 빔

대화 형 호출 ( 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 암호 를 묻는 대화 상자가 열립니다 .