.bashrc
쓰기 불가능한 파일을 자동으로 sudos하는 기능이 있습니다 .
vim() {
if [ -w "$1" ]; then
\vim "$1"
else
sudo env HOME="$HOME" \vim -u ~/.vimrc "$1"
fi
}
파일에 sudo가 필요한 경우 제대로 작동합니다. 그렇지 않은 경우 이 함수를 재귀적으로 호출하고 I CC까지 CPU를 100% 사용합니다.
이 답변에서여러 가지 옵션이 있으며 모두 시도해 보았습니다. 실제로 작동하는 것:
'vim' "$1" #fails
\vim "$1" #fails
command vim "$1" #Works!
다른 옵션이 예상대로 작동하지 않는 이유는 무엇입니까?
(중복인 건 알지만 현재 질문 제목으로는 SO/SE에서 답변을 찾기가 어렵기 때문에 나와 다른 사람들이 인터넷 검색을 통해 찾을 수 있는 제목으로 질문을 게시해야겠다고 생각했습니다.)
답변1
별칭 앞에 문자가 있으면 별칭이 실행되지 않습니다.
alias ls='ls -la'
ls foo.txt #will run ls -la foo.txt
\ls foo.txt #will run ls foo.txt
'ls' foo.txt #will run ls foo.txt
'ls foo.txt' #will run ls foo.txt
그러나 이것이 함수를 중지하는 것은 아니며, command
동일한 이름의 함수를 생성하는 경우 기본 내장 함수를 참조해야 합니다.
ls () {
echo "not an alias"
}
alias ls='echo "an alias"'
ls foo.txt #will echo "an alias"
\ls foo.txt #will echo "not an alias"
'ls' foo.txt #will echo "not an alias"
command ls foo.txt #will actually run `ls`
설명하다
문제는 처음 두 옵션이 별칭만 처리할 수 있다는 것입니다. 동일한 이름을 가진 함수나 명령이 있는지 감지하는 특수 리디렉션 연산자가 아닙니다. 별칭은 파이프나 명령의 첫 번째 부분인 경우에만 확장되므로 별칭 앞에 무언가를 넣는 것뿐입니다.
alias v='sudo vim'
v x.txt
#automatically expands "v" to "sudo vim" and then does the rest of the command
# v x.txt ==> sudo vim x.txt
Bash는 알고 있는 별칭 목록( 를 사용하여 얻을 수 있음)을 사용하여 alias
명령의 첫 번째 단어를 확장 하려고 합니다. 별칭은 인수를 사용하지 않으며 첫 번째 단어(공백으로 구분)만 가능합니다.vim x.txt
에 익숙해sudo vimim x.txt
올바르게 확장하려면 명령에서 위 별칭을 사용하여 확장하세요 .
그러나 작은따옴표 안의 내용은 확장되지 않습니다. 변수가 나타내는 내용 대신 echo '$USER'
리터럴이 인쇄됩니다 . $USER
또한 bash는 \x
( x
주로) 확장됩니다. 이는 별명을 이스케이프하기 위해 특별히 추가된 추가 메소드가 아니며 단지 bash 확장이 작성되는 방식의 일부일 뿐입니다. 따라서 이러한 방법을 사용하면 별칭이 명령을 숨기면서도 실제 명령에는 계속 액세스할 수 있습니다.
답변2
다른 옵션이 예상대로 작동하지 않는 이유는 무엇입니까?
명령줄이 실행되는 방법에 대한 세부 정보가 있기 때문입니다.
기본 개념은 명령줄의 첫 번째 단어가 쉘이 검색하여 실행하려고 하는 명령이라는 것입니다. 이 경우주문하다:
명령줄은 (대부분) 메타 문자로 구분됩니다.
메타문자
따옴표가 없을 때 단어를 구분하는 문자입니다. 다음 중 하나:
| & ( ) < > 공백 탭 개행첫 번째라면인용되지 않음word는 별칭 정의로 대체되는 별칭 단어와 일치합니다. 루프를 피하려면 다음을 수행하십시오.한 번새로운 첫 번째 단어가 확장되는 별칭과 일치하는 경우. 이렇게 하면 루프 없이 작업할 수 있습니다.
$ alias ls='ls -la' $ ls dir # will expand to `ls -la dir`
참고: 별칭 값의 마지막 문자가 비어 있으면 별칭 뒤의 다음 명령 단어도 별칭 확장을 확인합니다.
(생성된) 첫 번째 단어가 확장(예: a
$var
)인 경우 대체됩니다(따옴표가 없는 경우 IFS 토큰화(및 글로빙)의 영향을 받음).$ var='echo -e ' $ $var test '\twords' # will expand to `echo -e test words` test words
위의 확장 이후(선택적 변수 할당 이후) 생성된 첫 번째 단어는 다음 순서로 검색됩니다.
- 특수 내장 기능(POSIX 모드에서만)
- 기능
- 내장 기능
- 해시 명령(해싱에 대한 도움말 읽기)
- 외부 명령(
$PATH
디렉토리에서 검색)
발견된 첫 번째 일치 항목이 실행됩니다.
테스트를 위해 다음과 같은 방법으로 순서를 변경할 수 있습니다.
- 별칭을 우회하려면
\test
또는 다른 유형의 확장을 사용하세요. - 함수와 별칭을 무시하려면 를 사용하세요
command test
. - 내장된 기능을 실행하려면 를 사용하세요
builtin test
. - 외부 애플리케이션을 실행하려면 명시적 경로( )를 사용하십시오
/bin/test
.
따라서 함수는 다음과 같이 정의됩니다.
$ ls(){ ls; }
무한 루프에서 호출됩니다. 또한 동일한 첫 번째 단어에 대한 스크립트를 호출합니다. 그것은 다음과 같습니다:
#!/bin/bash
$0 "$@"
커널이 충돌할 때까지 동일한 스크립트가 루프에서 다시 실행됩니다(사용 중인 커널에 스크립트를 계속 호출하는 데 제한이 있는 경우).
이 시퀀스는 다음을 실행하여 표시됩니다 type -a
.
$ test(){ echo test function; }
$ alias test=test
$ type -a
test is aliased to `test'
test is a function
test ()
{
echo test function
}
test is a shell builtin
test is /usr/bin/test
질문에 정의된 함수는 별칭만 우회 \vim
하지만 함수는 우회하지 않습니다. 별칭과 기능을 우회하려면 명령을 사용하십시오. 이 함수는 필요한 작업을 수행해야 합니다.
vim() {
if [ -w "$1" ]; then
command vim "$1"
else
sudo HOME="$HOME" bash -c 'command vim "$@"' _ -u ~/.vimrc "$1"
fi
}
답변3
함수에 vim
호출 바이너리에 대한 전체 경로를 제공하면 재귀 루프가 발생하지 않습니다. 또한 -H
sudo 옵션을 사용하여 $HOME을 설정합니다.
vim() {
if [ -w "$1" ]; then
command vim "$1"
else
sudo env HOME="$HOME" \vim -u ~/.vimrc "$1"
fi
}
감사해요. 나는 이것을 기대하지 않았지만 이제 나도 .bashrc
그것을 가지고 있습니다.
편집하다:
업데이트된 호출 command vim
대신 sudo env
이렇게 sudo -h
하면 계속 머무를 루프가 없습니다.