如果我有一個文件
#!/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 開頭、後跟#!
.
對於yash
shell,如果 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