shebang이 있는지 확인하는 가장 빠른 방법

shebang이 있는지 확인하는 가장 빠른 방법

다음과 같은 파일이 있는 경우

#!/usr/bin/env foobar

이 파일에 해시뱅이 있는지 확인하는 가장 빠르고 최선의 방법은 무엇입니까? 처음 2바이트만 읽을 수 있다고 들었습니다. 어떻게?

답변1

와 함께 zsh:

if LC_ALL=C read -u0 -k2 shebang < file && [ "$shebang" = '#!' ]; then
  echo has shebang
fi

ksh93또는 와 동일 bash:

if IFS= LC_ALL=C read -rN2 shebang < file && [ "$shebang" = '#!' ]; then
  echo has shebang
fi

하지만 bashNUL로 시작하고 다음에 #!읽는 파일에 대해서는 오탐지를 제공합니다.모두예를 들어 선행 NUL 바이트는 truncate -s1T file한 번에 완전히 2바이트로 생성된 1테비바이트 파일을 읽습니다.

따라서 bash다음을 사용하는 것이 더 좋습니다.

IFS= LC_ALL=C read -rn2 -d '' shebang

읽혀진 것까지NUL로 구분된 레코드의 2바이트입니다.

read, [echo명령이 모두 내장되어 있으므로 프로세스를 포크하거나 추가 명령을 실행하지 않습니다 .

POSIXly에서는 다음을 수행할 수 있습니다.

if IFS= read -r line < file; then
  case $line in
    ("#!"*) echo has shebang
  esac
fi

전체 라인이 필요하다는 점에서 더 엄격합니다. 적어도 Linux에서는 유효한 shebang을 위해 개행 문자가 필요하지 않습니다.

그래서 당신은 할 수 있습니다 :

line=
IFS= read -r line < file
case $line in
  ("#!"*) echo has shebang
esac

일부 쉘은 한 번에 1바이트씩 잠재적으로 더 많은 바이트를 읽을 수 있다는 점에서 약간 덜 효율적입니다. 1TiB 스파스 파일을 사용하면 대부분의 셸에서 많은 시간이 소요됩니다(그리고 잠재적으로 많은 메모리를 사용하게 됩니다).

가 아닌 다른 쉘을 사용하면 zshNUL로 시작하고 뒤에 #!.

쉘을 사용하면 yashshebang에 현재 로케일에서 유효한 문자를 형성하지 않는 바이트 시퀀스가 ​​포함되어 있으면 실패합니다(shebang에 C 로케일에 ASCII가 아닌 문자가 포함되어 있으면 실패할 수도 있습니다(적어도 2.39 이상에서는). C 로케일은 모든 문자가 단일 바이트이고 모든 바이트 값이 유효한 --반드시 정의되지는 않더라도-- 문자를 형성하는 로케일을 의미하더라도)

내용이 로 시작하는 모든 파일을 찾으려면 다음을 #!수행할 수 있습니다.

PERLIO=raw find . -type f -size +4c -exec perl -T -ne '
  BEGIN{$/=\2} print "$ARGV\n" if $_ eq "#!"; close ARGV' {} +

우리는 크기가 최소 5바이트( #!/x\n최소 현실적인 shebang)인 파일만 고려하고 있습니다.

  • 를 사용하면 가능한 -exec perl... {} +한 많은 파일 경로를 전달하므로 perl가능한 적은 호출을 실행합니다.
  • -T해결하는 것입니다그 제한perl -n또한 이름이 ASCII 공백 문자 또는 로 끝나는 파일에서는 작동하지 않음을 의미합니다 |.
  • PERLIO=rawperlIO 버퍼링 계층 없이 직접 시스템 호출을 사용하게 하므로 read()(파일 이름 인쇄에도 영향을 미침) 크기 2의 읽기를 수행합니다.
  • $/ = \2레코드 구분 기호가 숫자에 대한 참조로 설정되면 레코드가 고정 길이가 됩니다.
  • close ARGV첫 번째 레코드를 읽은 후 현재 파일의 나머지 부분을 건너뜁니다.

답변2

다음에서 자신만의 "마법 패턴"을 정의 /etc/magic하고 file테스트하는 데 사용할 수 있습니다.

$ sudo vi /etc/magic
$ cat /etc/magic
# Magic local data for file(1) command.
# Insert here your local magic data. Format is described in magic(5).
0 byte 0x2123 shebang is present
$ cat /tmp/hole2.sh #To prove [1] order of hex [2] 2nd line ignored
!#/bin/bash 
#!/bin/bash
$ cat /tmp/hole.sh 
#!/bin/bash
$ file /tmp/hole2.sh 
/tmp/hole2.sh: ASCII text
$ file /tmp/hole.sh 
/tmp/hole.sh: shebang is present
$ file -b /tmp/hole.sh #omit filename
shebang is present

0x212316진수는 '#!'입니다. 역순으로:

$ ascii '#' | head -n1
ASCII 2/3 is decimal 035, hex 23, octal 043, bits 00100011: prints as `#'
$ ascii '!' | head -n1
ASCII 2/1 is decimal 033, hex 21, octal 041, bits 00100001: prints as `!'

선택적으로 다음을 넣을 수 있습니다.

0 string \#\! shebang is present

참조: man 5 magic, man 1 file, man 1posix file

답변3

그렇게 해야 합니다:

if [ "`head -c 2 infile`" = "#!" ]; then
    echo "Hashbang present"
else
    echo "no Hashbang present"
fi

답변4

grep단일 라이너 솔루션에서 사용

if head -1 file | grep "^#\!" > /dev/null;then echo "true"; fi

관련 정보