もしファイルがあったら
#!/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
ただし、bash
NULで始まり、その後に続くファイルに対しては誤検出が発生し#!
、全てtruncate -s1T file
先頭の NUL バイトは、たとえば 2 バイトで作成された 1 テビバイトのファイルを一度に読み取ることになります。
したがってbash
、 の場合は、次のように使用する方がよいでしょう。
IFS= LC_ALL=C read -rn2 -d '' shebang
それは読むまでNUL で区切られたレコードの 2 バイト。
これらはプロセスをフォークしたり、 のように追加のコマンドを実行したりせずread
、コマンド[
はecho
すべて組み込まれています。
POSIX では、次のことができます。
if IFS= read -r line < file; then
case $line in
("#!"*) echo has shebang
esac
fi
完全な行も必要となるため、より厳密です。ただし、少なくとも Linux では、有効なシェバンには改行は必要ありません。
つまり、次のようにすることができます:
line=
IFS= read -r line < file
case $line in
("#!"*) echo has shebang
esac
一部のシェルでは 1 バイトずつ読み取るため、より多くのバイトを読み取る可能性があるという点で、効率はわずかに低くなります。1TiB のスパース ファイルの場合、ほとんどのシェルでかなりの時間がかかります (また、大量のメモリを使用する可能性もあります)。
以外のシェルではzsh
、NUL で始まり、その後に が続くファイルに対して誤検知が発生する可能性もあります#!
。
シェルではyash
、シェバンに現在のロケールで有効な文字を形成しないバイトシーケンスが含まれている場合、失敗します (C ロケールでは、すべての文字が 1 バイトで、すべてのバイト値が有効な (必ずしも定義されていない場合でも) 文字を形成することを意図しているにもかかわらず、シェバンに C ロケールで非 ASCII 文字が含まれている場合も失敗します (少なくとも 2.39 以前では))。
内容が で始まるすべてのファイルを検索する場合は#!
、次のようにします。
PERLIO=raw find . -type f -size +4c -exec perl -T -ne '
BEGIN{$/=\2} print "$ARGV\n" if $_ eq "#!"; close ARGV' {} +
少なくとも 5 バイト (#!/x\n
現実的な最小のシェバン) の大きさのファイルのみを検討します。
- では
-exec perl... {} +
、できるだけ多くのファイルパスを に渡し、perl
できるだけ少ない呼び出しを実行します。 -T
回避することですその制限perl -n
また、名前が ASCII スペース文字または で終わるファイルでは機能しません|
。PERLIO=raw
perl
IO バッファリング層なしでシステム コールを直接使用するようにし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
0x2123
'#!' の逆順の16進数です:
$ 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