web-dev-qa-db-ja.com

BashでファイルにUTF-8 BOMがあるかどうかを検出するにはどうすればよいですか?

ファイルから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でこれを回避できるオプションを探しましたが、うまくいきませんでした。これを機能させるために私にできることはありますか?

24
James Ko

まず、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はサポートしていません。

ノート:

  1. 明示的なreturn $?の使用はオプションです。この関数は、デフォルトでは、最後に実行されたコマンドの終了コードで戻ります。

  2. 関数の定義にはPOSIXフォームを使用しました。これはbashフォームと同等ですが、別のシェルで関数を実行する必要がある場合に対処する問題が1つ少なくなります。

  3. bashは関数名での文字-の使用を受け入れますが、これは物議を醸す機能です。より広く受け入れられている_に置き換えました。 (この問題の詳細については、 この答え を参照してください。)

  4. grep-qオプションは、それを静かにします。つまり、適切な終了コードを設定しますが、文字をstdoutに送信しません。

24
John1024

最初の読み取り行に以下を適用しました。

read c
if (( "$(printf "%d" "'${c:0:1}")" == 65279 ))  ; then c="${c:1}" ; fi

これは単に変数からBOMを削除するだけです。

0
apexik