왜! ! 별칭 내에서는 작동하지 않나요?

왜! ! 별칭 내에서는 작동하지 않나요?

/etc/bashrc시스템 파일에 다음 별칭이 설정되어 있습니다 .

alias root="sudo !!"

이것의 목적은 sudo코스를 사용하여 마지막으로 사용한 명령을 실행하는 것입니다. 사용하면 history대화형 쉘에서 bashrc실행할 때 얻는 실제 명령 이 아니라 쉘이 초기화될 때 파일의 마지막 명령을 대체합니다 . sudo !!저도 해봤는데 alias root="sudo fc -s"별 효과 없었어요.

이것이 BASH가 명령 대체를 수행하는 방식과 관련이 있을 수 있다는 것을 알고 있지만, 왜 이런 일이 발생하는지 설명하고 사용 가능한 대체품을 제공할 수 있는 사람이 있습니까?

저는 BASH 버전 3.2.51(1)-릴리스(x86_64-apple-darwin13)를 실행하고 있습니다.

답변1

bash 맨페이지의 2비트는 이 동작의 주요 부분을 설명합니다.

HISTORY EXPANSION섹션의:

히스토리 확장은 쉘이 행을 단어로 나누기 전에 전체 행을 읽은 후 즉시 수행됩니다.

ALIASES섹션의:

각 단순 명령의 첫 번째 단어(따옴표가 없는 경우)를 검사하여 별칭이 있는지 확인합니다.

따라서 기본적으로 역사적 확장은 분사 이전에 발생합니다. 별칭 확장은 나중에 발생합니다.


대체 솔루션

내가 생각할 수 있는 가장 좋은 방법은 다음과 같습니다.

alias root='sudo $(fc -ln -1)'

이는 간단한 명령에는 잘 작동하지만 더 복잡한 명령에는 조정이 필요합니다.

alias root='sudo sh -c "$(fc -ln -1)"'

변경 이유는 다음과 같습니다.

# alias root='sudo $(fc -ln -1)'
# echo "I AM $(whoami)"
I AM patrick
# root
"I AM $(whoami)"

보시다시피 쉘 구문 분석이 수행되지 않았습니다. use 로 변경하면 sh -c "..."쉘 해석이 가능합니다.

# alias root='sudo sh -c "$(fc -ln -1)"'
# echo "I AM $(whoami)"
I AM patrick
# root
I AM root

다른 방법(저는 이것을 먼저 생각했기 때문에 답변에 그대로 두겠습니다. 그러나 위의 방법만큼 좋지는 않습니다):

alias root='fc -e "sed -i -e \"s/^/sudo /\""'

fc -e명령은 지정된 명령을 실행하고 이전에 실행된 명령이 포함된 파일을 전달합니다. 해당 파일을 실행 sed하고 명령 앞에 sudo.

답변2

이런 방식으로 별칭을 사용할 수 없습니다. 별칭은 와 같은 매개변수를 전달할 수 없습니다 !!. 원하는 효과를 얻으려면 함수를 대신 사용할 수 있습니다.

function root() {
  sudo $(history | tail -2 | head -1 | awk '{$1=$2=$3=""; print $0}');
}

그러나 이는 대략적인 생각이며 몇 가지 문제가 있을 수 있습니다. 내 기록 명령 출력은 다음과 같습니다.

$ history
1081  20131205 08:00:12  ls
1082  20131205 08:00:13  history

따라서 이 출력을 구문 분석해야 합니다. 위에서는 기록을 실행하여 마지막 2개의 명령을 가져온 다음 이전에 실행되었던 명령인 마지막 2개의 명령 중 첫 번째 명령을 가져옵니다. 그런 다음 awk이전에 실행했던 명령줄을 그대로 두고 처음 4개 열을 삭제 했습니다 .

별칭으로?

우리가 출력을 사용하고 있다는 점을 고려하면 history더 이상 Bash 기능을 사용할 이유가 없습니다. 이전 명령을 매개변수로 전달하려는 경우 이 작업을 수행해야 하지만 history지금은 이 명령을 통해 가져옵니다.

$ alias root="sudo \$(history | tail -2 | head -1 | awk '{\$1=\$2=\$3=\"\"; print \$0}')"

위의 내용은 별칭으로 변환하는 데 필요한 더 까다로운 이스케이프 처리를 제외하고 이 함수와 유사하게 작동합니다.

관련 정보