確定 shebang 是否存在的最快方法

確定 shebang 是否存在的最快方法

如果我有一個文件

#!/usr/bin/env foobar

確定該檔案是否有 hashbang 的最快/最好的方法是什麼?我聽說你只能讀取前 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

但對於以 NUL 開頭、後跟和 的bash檔案會產生誤報#!全部truncate -s1T file例如,前導 NUL 位元組將讀取一次使用 2 個位元組建立的 1 tebibyte 檔案。

因此bash,使用 ,最好使用:

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

也就是讀到的取決於2 個位元組的 NUL 分隔記錄。

這些不會分叉進程,也不會執行額外的命令,因為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

它的效率稍低,因為它可能會讀取更多字節,而某些 shell 一次只能讀取一個位元組。對於我們的 1TiB 稀疏文件,在大多數 shell 中這將花費大量時間(並且可能使用大量記憶體)。

對於除此之外的 shell zsh,它也可能會對以 NUL 開頭、後跟#!.

對於yashshell,如果 shebang 包含在當前語言環境中不形成有效字元的位元組序列,則會失敗(如果 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=raw導致直接perl使用read()系統呼叫而無需任何 IO 緩衝層(也會影響檔案名稱的列印),因此它將執行大小為 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

0x2123是十六進制的“#!”按相反順序:

$ 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

相關內容