如何检测文件是否在Bash中具有UTF-8 BOM?

Jam*_* Ko 23 unix linux bash encoding utf-8

我正在尝试编写一个脚本,它将自动从文件中删除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 $?
}
Run Code Online (Sandbox Code Playgroud)

出于某种原因,head似乎忽略了文件前面的BOM.举个例子,运行这个

printf '\xef\xbb\xbf' > file
head -c 3 file
Run Code Online (Sandbox Code Playgroud)

不会打印任何东西.

我试着找一个选项head --help让我解决这个问题,但没有运气.有什么我可以做的工作吗?

Joh*_*024 23

首先,让我们演示head实际上是否正常工作:

$ printf '\xef\xbb\xbf' >file
$ head -c 3 file 
$ head -c 3 file | hexdump -C
00000000  ef bb bf                                          |...|
00000003
Run Code Online (Sandbox Code Playgroud)

现在,让我们创建一个工作函数has_bom.如果您的grep支持-P,那么一个选项是:

$ has_bom() { head -c3 "$1" | LC_ALL=C grep -qP '\xef\xbb\xbf'; }
$ has_bom file && echo yes
yes
Run Code Online (Sandbox Code Playgroud)

目前,只有GNU grep支持-P.

另一种选择是使用bash $'...':

$ has_bom() { head -c3 "$1" | grep -q $'\xef\xbb\xbf'; }
$ has_bom file && echo yes
yes
Run Code Online (Sandbox Code Playgroud)

ksh并且zsh还支持$'...'但是这个结构不是POSIX并且dash不支持它.

笔记:

  1. 使用explicit return $?是可选的.默认情况下,该函数将返回上一个命令运行的退出代码.

  2. 我使用POSIX表单来定义函数.这相当于bash表单,但如果你必须在另一个shell下运行该函数,则可以减少一个问题.

  3. bash确实接受-函数名中字符的使用,但这是一个有争议的特性.我用_更广泛接受的替换它.(有关此问题的更多信息,请参阅此答案.)

  4. 使其安静的-q选项grep,这意味着它仍设置正确的退出代码,但它不会向stdout发送任何字符.

  • 嗯,从来不知道 Bash 支持十六进制字符串文字。无论如何,感谢您的出色回答! (2认同)