40_custom 파일에서“exec tail -n +3 $ 0”줄의 의미


17

grub 구성 파일을 이해하려고합니다. 따라서이 과정에서 /etc/grub.d/40_custom 파일을 발견했습니다 . 내 파일에는 다음 줄이 포함되어 있습니다.

#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.
menuentry "Windows 10" --class windows --class os {
insmod part_msdos
savedefault
insmod ntfs
insmod ntldr
set root='(hd0,msdos1)'
ntldr ($root)/bootmgr
}

내 시스템은 이중 부팅이므로 분명히 이것은 Windows 10 용 부트 로더입니다.

내 질문은이 부분 exec tail -n +3 $0입니다.
내가 올바르게 해독하는 경우 이것은 +3파일 의 세 번째 줄 ( ) 에서 시작하여 마지막 줄을 인쇄한다는 의미 $0입니다. $0물론이 경우 실제 파일 /etc/grub.d/40_custom 입니다.

그렇다면 왜이 명령을 40_custom 파일 에서 사용 합니까? 내가 그것을 얻을 때 출력이 완전히 생략되면 출력은 동일합니다. 내가 생각할 수있는 유일한 것은 통역사를 식별하는 첫 번째 줄입니다.

#!/bin/sh

그러나 그런 다음 다시 실행 exec tail -n +3 $0됩니다. 그렇다면 이것은 단지 쓸모없는 규칙입니까?

답변:


16

트릭은 무엇을 하는가입니다 exec.

$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
    Replace the shell with the given command.

    Execute COMMAND, replacing this shell with the specified program.
    ARGUMENTS become the arguments to COMMAND.  If COMMAND is not specified,
    any redirections take effect in the current shell.

exec,이 경우 쉘이 지정된 것으로 대체됩니다 tail. 다음은 실제로 사용되는 예입니다.

$ cat ~/foo.sh
#!/bin/sh
exec tail -n +3 "$0"
echo foo

$ ./foo.sh
echo foo

따라서 echo셸을 변경하고 tail대신 사용하기 때문에 명령이 실행되지 않습니다 . 우리가 제거하면 exec tail:

$ cat ~/foo.sh
#!/bin/sh
echo foo
$ ./foo.sh
foo

따라서 이것은 자신의 내용을 출력하는 것이 유일한 작업 인 스크립트를 작성할 수있는 깔끔한 트릭입니다. 아마도 모든 호출 40_custom은 내용으로 출력을 기대합니다. 물론 이것은 왜 tail -n +3 /etc/grub.d/40_custom직접 달리지 않는지에 대한 의문을 불러 일으킨다 .

답은 grub 자체 스크립팅 언어 를 사용하기 때문에이 해결 방법이 필요하기 때문입니다.


좋은 대답입니다! 그러나 우리 #!/bin/tail -n +2가 쉘뱅으로 쓰면 어떨까요? 파일의 나머지 부분을 인쇄합니까?
발은

@val 그것을 시도하고보십시오 :) 그것이 shebang으로 완벽하게 작동하지 않는 것으로 나타났습니다. -n +2로 해석되어 -n 2마지막 두 줄만 인쇄됩니다. 그것은 아마도 자체 질문의 가치가 있습니다.
terdon

3
@val ... shebang 동작은 예상보다 훨씬 덜 표준화되고 이식 가능합니다. en.wikipedia.org/wiki/Shebang_(Unix)#Portability
Charles Duffy

@val nand 사이의 공백을 제거하면 Linux에서 작동 합니다 +. Linux에서 최소한 실행 파일 경로와 공백 뒤에 다음 문자가 단일 인수로 처리됩니다. 따라서 공백을 사용하면 tail은 공백을보고 숫자에 도달 할 때까지 유효하지 않은 접두사 -n의 인수 (이 경우 공백과 a +) 를 제거하기로 결정합니다 . 그러나 Charles Duffy가 말한 것처럼 현재의 방식은 다른 Unices보다 이식성이 뛰어납니다.
JoL

1
@fluffy 그들은 여기 의사를 사용할 있습니다. 내 답변에서 Fedora 설명서의 링크를 참조하십시오. 그들은 정확히 cat <<EOF ...EOF거기에서 사용합니다
Sergiy Kolodyazhnyy

9

디렉토리 /etc/grub.d/에는 많은 실행 파일이 포함되어 있습니다 (일반적으로 쉘 스크립트이지만 다른 실행 파일 유형도 가능합니다). grub-mkconfig실행될 때마다 (예 :을 실행 update-grub하지만 업데이트 된 커널 패키지를 설치할 때 (일반적으로 패키지 관리자에게 업데이트하도록 지시하는 설치 후 후크가 있음 grub.cfg), 모두 알파벳 순서로 실행됩니다. 그들의 출력은 모두 연결되어 파일에서 끝나고 파일 /boot/grub/grub.cfg에서 어떤 부분이 나오는지 보여주는 깔끔한 섹션 헤더가 /etc/grub.d/있습니다.

이 특정 파일 40_custom은 입력 / 줄 grub.cfg을이 파일에 입력 / 붙여 넣기 만하면 쉽게 입력 / 줄을 추가 할 수 있도록 설계되었습니다 . 동일한 디렉토리에있는 다른 스크립트는 커널 또는 비 Linux 운영 체제를 찾고 메뉴 항목을 작성하는 등의 복잡한 작업을 수행합니다.

grub-mkconfig모든 파일을 동일한 방식으로 처리 (실행 및 출력) 할 수 있도록 하기 위해 40_custom스크립트이며이 exec tail -n +3 $0메커니즘을 사용 하여 해당 내용 ( "헤더"제외)을 출력합니다. 실행 파일이 아닌 update-grub경우이 파일의 리터럴 텍스트 내용을 다른 모든 파일과 달리 실행하는 대신 특수 하드 코딩 된 예외가 필요합니다. 그러나 당신 (또는 다른 리눅스 배포판의 제작자) 이이 파일에 다른 이름을 부여하고 싶다면 어떻게해야합니까? 또는 예외에 대해 모르고 이름이 셸 스크립트 인 경우 40_custom어떻게해야합니까?

GNU GRUB 매뉴얼 에 대한 자세한 내용 grub-mkconfigGNU GRUB 매뉴얼 (주로 설정할 수있는 옵션에 대한 설명이 대부분 임 )을 읽을 수 있으며 이러한 파일이 실행 되도록하는 파일도 있어야합니다 ./etc/grub.d/*/etc/default/grub/etc/grub.d/READMEgrub.cfg


1
terdon의 대답은 라인의 작동 방식을 설명하지만 GRUB이 왜 이런 식으로 일을하는지에 대한 더 합리적인 설계 이유를 제시합니다.
JoL

좋은 대답입니다. 특별한 예외에 대한 요점으로, "더 간단한"예외는 /etc/grub.d/exec실행 가능한 파일 / 스크립트, /etc/grub.d/static일반 텍스트 파일 또는이를 구별하기위한 다른 표시기 등 두 개의 디렉토리가있을 수 있습니다 . 그러나 이것이 그들이 결정한 디자인 결정이었습니다.
Stobor

3

TL; DR : 파일에 새 항목을 간단하게 추가하는 것은 속임수입니다.

요점은 그루브의 우분투 위키 페이지 중 하나에 설명되어 있습니다 .

  1. update-grub을 실행하는 동안 실행 파일 만 grub.cfg에 출력을 생성합니다.

스크립트 출력은 파일 /etc/grub.d/내용이 grub.cfg됩니다.

이제 무엇을 exec합니까? 전체 스크립트에 대한 출력을 다시 배선하거나 명령이 제공된 경우 언급 된 명령이 스크립트 프로세스를 수행하고 대체합니다. PID 1234를 사용한 쉘 스크립트는 PID 1234를 tail사용한 명령입니다.

이제 tail -n +3 $0스크립트 자체의 세 번째 줄 다음에 모든 것을 인쇄 한다는 것을 이미 알고 있습니다. 왜 우리는 이것을해야합니까? grub이 출력에만 관심이 있다면 우리도 할 수 있습니다

cat <<EOF
    menuentry {
    ...
    }
EOF

실제로, 다른 목적이 있더라도 Fedora documentationcat <<EOF 에서 예제를 찾을 수 있습니다. 요점은 주석에 있습니다-사용자의 사용 편의성 :

# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.

exec트릭을 사용하면 무엇을하는지 cat <<EOF(스포일러, here-doc 라고 함 ) 알 필요가 없으며 EOF마지막 줄 에을 추가해야합니다 . 파일에 메뉴 항목을 추가하고 완료하십시오. 또한 메뉴 항목을 추가하여 스크립팅하는 경우 간단히 >>쉘에서 via 를이 파일에 추가 할 수 있습니다 .

또한보십시오:


그러나 왜 grub이 파일을 직접 읽지 않았습니까? 왜 그들이 대신 실행 가능하도록 선택했는지 알고 있습니까? 프로세스가 메뉴를 생성하는 모든 프로세스에서 읽은 간단한 텍스트 파일로 만드는 것이 훨씬 간단하지만 대신 실행 가능하게하고이를 (단순하지만) 복잡한 해결 방법으로 추가했습니다. 내 대답에 긍정하는 것처럼 grub에 자체 스크립팅 언어가 있기 때문입니까?
terdon

@ terdon 나는 이것이 grub 언어 자체와 관련이 있다고 생각하지 않습니다. #!/bin/sh이 경우에는 필요하지 않습니다 . 나는 이것이 단순히 역사적인 이유 ( PUPA 코드베이스 에서 전달됨 )이며 SysV 유형의 스크립팅에서 영감을 얻은 디자인 결정이라고 생각합니다.
Sergiy Kolodyazhnyy

@terdon 이것은 실제로 질문에 영감을주었습니다 : unix.stackexchange.com/q/492966/85039
Sergiy Kolodyazhnyy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.