Estou trabalhando em uma instância WSL (Ubuntu) em uma máquina Windows 10.
Para encontrar alguma informação em um banco de dados, gerei um script contendo toda a estrutura e conteúdo do banco de dados, e esperava que de forma simples grep
pudesse me dizer se alguma informação está presente ou não.
Isso, no entanto, não funcionou, como você pode ver:
WSL_Prompt> grep "S" DB_Local_Backup_20250311.sql
=> Você tá brincando? Não tem nenhuma letra "S" em todo esse banco de dados?
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
=> A letra "S" está presente em quase todos os lugares desse arquivo.
WSL_Prompt> ls -ltra DB_Local_Backup_20250311.sql
-rwxrwxrwx 1 scampsd scampsd 4575828864 Mar 11 11:35 DB_Local_Backup_20250311.sql
=> Ok, admito: o arquivo é bem grande.
WSL_Prompt> grep --version | head -n 1
grep (GNU grep) 3.4
=> aqui está a versão que grep
estou usando.
WSL Prompt> cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
=> aqui está a versão do WSL que estou usando.
Mais algumas informações:
Tipo de arquivo:
WSL_Prompt> file DB_Local_Backup_20250311.sql
DB_Local_Backup_20250311.sql: Little-endian UTF-16 Unicode text, with CRLF line terminators
Despejo hexadecimal:
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
Existe uma solução?
grep
não tem nenhum limite de tamanho de arquivo até onde eu saiba. É muito mais provável que seja um problema de codificação. Provavelmente há muitos pontos de código UTF-16, UTF-32 e até UTF-8 que não são codificados como 83 e cujo glifo se parece comS
. O grep clássico tende a assumir a codificação ASCII.A solução que eu usaria é identificar a codificação da seguinte forma
Onde está o encantamento atual para hexdump canônico na sua distribuição/sistema operacional?
hd -c
hd -C
Então você pode procurar uma sequência de bytes usando escapes hexadecimais, se necessário.
Seu arquivo é codificado em UTF-16 , little endian (LE) com uma marca de ordem de byte (BOM) e com terminações de linha Microsoft-Windows (CR, LF) em vez de terminações de linha Unix (LF). Então cada letra é escrita em um arquivo como dois bytes em vez do byte único que versões antigas do grep poderiam esperar. O arquivo, portanto, também contém uma marca de ordem de byte (BOM) nos dois primeiros bytes e um nulo antes do valor ASCII de 'S'. Qualquer um desses pode perturbar versões antigas do grep, mas acho estranho que o grep moderno tenha um problema. Eu tentaria
grep --binary-files=text S filename
.Em vez de grep eu também tentaria algo como
ou
PS Veja É um arquivo ANSI ou UTF8? para mais informações sobre o que a Microsoft chama enganosamente de "Unicode" e "ANSI"
PPS
Comentário do autor da pergunta :
Obviamente, a solução mais fácil é certificar-se de que o arquivo mencionado não tenha essa codificação estranha para começar. Isso pode ser resolvido salvando o script gerado pelo SQL-Server como texto ANSI, como pode ser feito a partir desta configuração:
grep é uma ferramenta tradicional que tem suas limitações. Codificações multibyte, como UTF-16 que você mencionou, são uma delas - ele não consegue lidar com elas corretamente.
Em vez de mexer manualmente nas codificações, use uma ferramenta grep mais moderna, como o ugrep .
Ele tenta detectar automaticamente o que a entrada usa. Ele funciona até mesmo com arquivos binários. Tudo o que você precisa fazer é instalá-lo (
apt install ugrep
no Ubuntu) e alterar o executável no seu comando: