我正在Windows 10 机器上开发WSL实例(Ubuntu)。
为了在数据库中查找某些信息,我生成了一个脚本,其中包含数据库的整个结构和grep
内容,我希望它可以简单地告诉我某些信息是否存在。
然而,正如您所看到的,这并没有起作用:
WSL_Prompt> grep "S" DB_Local_Backup_20250311.sql
=> 你在开玩笑吗?整个数据库中没有字母“S”?
WSL_Prompt> head -5 DB_Local_Backup_20250311.sql
USE [DB_Name]
GO
/****** Object: User [DB_user] Script Date: 11/03/2025 11:32:44 ******/
CREATE USER [DB_user] WITHOUT LOGIN WITH DEFAULT_SCHEMA=[dbo]
GO
=> 字母“S”几乎出现在该文件的所有地方。
WSL_Prompt> ls -ltra DB_Local_Backup_20250311.sql
-rwxrwxrwx 1 scampsd scampsd 4575828864 Mar 11 11:35 DB_Local_Backup_20250311.sql
=> 好吧,我承认:这个文件确实很大。
WSL_Prompt> grep --version | head -n 1
grep (GNU grep) 3.4
grep
=> 这是我正在使用的版本。
WSL Prompt> cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
=> 这是我正在使用的 WSL 的版本。
更多信息:
文件类型:
WSL_Prompt> file DB_Local_Backup_20250311.sql
DB_Local_Backup_20250311.sql: Little-endian UTF-16 Unicode text, with CRLF line terminators
十六进制转储:
WSL_Prompt> head -n 1 DB_Local_Backup_20250311.sql | hd -c
00000000 ff fe 55 00 53 00 45 00 20 00 5b 00 43 00 65 00 |..U.S.E. .[.C.e.|
0000000 U \0 S \0 E \0 \0 [ \0 C \0 e \0
有解决办法吗?
grep
据我所知,没有任何文件大小限制。这更可能是编码问题。可能有很多 UTF-16、UTF-32 甚至 UTF-8 代码点未编码为 83,其字形看起来像S
。经典 grep 倾向于假设 ASCII 编码。我将使用的解决方案是按如下方式识别编码
您的发行版/操作系统上规范的十六进制转储的当前咒语在哪里。
hd -c
hd -C
然后,您可以根据需要使用十六进制转义符来 grep 字节序列。
您的文件采用UTF-16编码,小端字节序 (LE),带有字节顺序标记 (BOM),并且使用 Microsoft-Windows 行尾符号 (CR、LF),而不是 Unix 行尾符号 (LF)。因此,每个字母都以两个字节写入文件,而不是旧版 grep 可能期望的单字节。因此,该文件的前两个字节还包含字节顺序标记 (BOM),在 ASCII 值“S”之前包含一个空值。这两种情况都可能破坏旧版 grep,但我觉得现代 grep 有问题,这很奇怪。我会尝试
grep --binary-files=text S filename
。除了 grep 我还会尝试类似
或者
PS 请参阅它是 ANSI 还是 UTF8 文件?以了解更多有关 Microsoft误导性地称为“Unicode”和“ANSI”的信息
聚苯硫醚
问题作者的评论:
显然,最简单的解决方案是确保所提及的文件一开始就没有那种奇怪的编码。可以通过将 SQL-Server 生成的脚本保存为 ANSI 文本来解决这个问题,如下所示:
grep 是一种传统工具,有其局限性。多字节编码(例如您提到的 UTF-16)就是其中之一 - 它无法正确处理它们。
不要手动处理编码,而是使用更现代的 grep 工具,例如ugrep。
它会尝试自动检测输入的内容。它甚至可以处理二进制文件。您所要做的就是安装它(
apt install ugrep
在 Ubuntu 上)并在命令中更改可执行文件: