ファイルからUTF-8 BOMを自動的に削除するスクリプトを記述しようとしています。そもそもファイルにファイルがあるかどうかを検出できません。これが私のコードです:
function has-bom {
# Test if the file starts with 0xEF, 0xBB, and 0xBF
head -c 3 "$1" | grep -P '\xef\xbb\xbf'
return $?
}
何らかの理由で、head
はファイルの前のBOMを無視しているようです。例として、これを実行する
printf '\xef\xbb\xbf' > file
head -c 3 file
何も印刷されません。
head --help
でこれを回避できるオプションを探しましたが、うまくいきませんでした。これを機能させるために私にできることはありますか?
まず、head
が実際に正しく機能していることを示しましょう。
$ printf '\xef\xbb\xbf' >file
$ head -c 3 file
$ head -c 3 file | hexdump -C
00000000 ef bb bf |...|
00000003
次に、機能する関数has_bom
を作成します。 grep
が-P
をサポートしている場合、1つのオプションは次のとおりです。
$ has_bom() { head -c3 "$1" | LC_ALL=C grep -qP '\xef\xbb\xbf'; }
$ has_bom file && echo yes
yes
現在、GNU grep
は-P
のみをサポートしています。
別のオプションは、bashの$'...'
を使用することです。
$ has_bom() { head -c3 "$1" | grep -q $'\xef\xbb\xbf'; }
$ has_bom file && echo yes
yes
ksh
およびzsh
も$'...'
をサポートしていますが、この構成はPOSIXではなく、dash
はサポートしていません。
ノート:
明示的なreturn $?
の使用はオプションです。この関数は、デフォルトでは、最後に実行されたコマンドの終了コードで戻ります。
関数の定義にはPOSIXフォームを使用しました。これはbashフォームと同等ですが、別のシェルで関数を実行する必要がある場合に対処する問題が1つ少なくなります。
bashは関数名での文字-
の使用を受け入れますが、これは物議を醸す機能です。より広く受け入れられている_
に置き換えました。 (この問題の詳細については、 この答え を参照してください。)
grep
の-q
オプションは、それを静かにします。つまり、適切な終了コードを設定しますが、文字をstdoutに送信しません。
最初の読み取り行に以下を適用しました。
read c
if (( "$(printf "%d" "'${c:0:1}")" == 65279 )) ; then c="${c:1}" ; fi
これは単に変数からBOMを削除するだけです。