Como analisar corretamente os nomes dos arquivos no Bash

As convenções de nomenclatura de arquivo Bash são muito ricas e é fácil criar um script ou uma linha que analisa nomes de arquivo incorretamente. Aprenda a analisar os nomes dos arquivos corretamente e, assim, garantir que seus scripts funcionem conforme o planejado!
O problema de analisar corretamente os nomes dos arquivos no Bash
Se você já usa o Bash há algum tempo e faz scripts em sua rica linguagem Bash, provavelmente já se deparou com alguns problemas de análise de nome de arquivo. Vamos dar uma olhada em um exemplo simples do que pode dar errado:
toque em 'a > b '

Aqui criamos um arquivo que possui um CR (retorno de carro) real introduzido pressionando enter após o a. As convenções de nomenclatura de arquivos Bash são muito ricas e, embora de certa forma sejam legais, podemos usar caracteres especiais como esses em um nome de arquivo, vamos ver como este arquivo se sai quando tentamos realizar algumas ações sobre ele:
ls | xargs rm

Isso não funcionou. xargs pegará a entrada de ls (por meio do | pipe) e a passará para rm, mas algo deu errado no processo!
O que deu errado é que a saída de ls é interpretada literalmente por xargs e a tecla & # 8216; enter &’ (CR – Carriage Return) dentro do nome do arquivo é visto por xargs como um caractere de terminação real, não um CR a ser passado para rm como deveria ser.
Vamos exemplificar isso de outra maneira:
ls | xargs -I {} echo '{} |'

É claro: xargs está processando a entrada como duas linhas individuais, dividindo o nome do arquivo original em dois! Mesmo que consertássemos os problemas de espaço por meio de uma análise sofisticada usando sed, logo encontraríamos outros problemas quando começarmos a usar outros caracteres especiais, como espaços, barras invertidas, aspas e muito mais!
toque em 'a b' toque em 'a b' toque em 'a \ b' toque em 'a "b' toque em" a'b "ls

Mesmo se você for um desenvolvedor Bash experiente, você pode tremer ao ver nomes de arquivo como este, pois seria muito complexo, para a maioria das ferramentas Bash comuns, analisar esses arquivos corretamente. Você teria que fazer todos os tipos de modificações de string para fazer isso funcionar. Ou seja, a menos que você tenha a receita secreta.
Antes de mergulharmos nisso, há mais uma coisa – um must-know – que você pode encontrar ao analisar a saída ls. Se você usar codificação de cores para listagens de diretório, que é habilitado por padrão no Ubuntu, é fácil encontrar outro conjunto de problemas de análise ls.
Eles não estão realmente relacionados a como os arquivos são nomeados, mas sim a como os arquivos são apresentados como saída de ls. A saída ls conterá códigos hexadecimais que representam a cor a ser usada em seu terminal.
Para evitar encontrá-los, simplesmente use --color = never como uma opção para ls: ls --color = never.
No Mint 20 (um excelente sistema operacional derivado do Ubuntu), esse problema parece corrigido, embora o problema ainda possa estar presente em muitas outras versões ou em versões anteriores do Ubuntu, etc. Eu vi esse problema recentemente em meados de agosto de 2020 no Ubuntu.
Mesmo se você não usar um código de cores para suas listagens de diretório, é possível que seu script seja executado em outros sistemas que não sejam de sua propriedade ou gerenciados por você. Nesse caso, você também desejará usar esta opção para impedir que os usuários de tal máquina executem o problema descrito.
Voltando à nossa receita secreta, vamos ver como podemos ter certeza de que não teremos problemas com caracteres especiais em nomes de arquivo Bash. A solução fornecida evita todo o uso de ls, o que seria bom evitar em geral, portanto, os problemas de codificação de cores também não são aplicáveis.
Ainda há momentos em que a análise de ls é rápida e prática, mas sempre será complicada e provavelmente & # 8216; suja &’ assim que os caracteres especiais forem introduzidos – para não falar de inseguro (caracteres especiais podem ser usados para introduzir todos os tipos de problemas).
A receita secreta: rescisão NULL
Os desenvolvedores da ferramenta Bash perceberam esse mesmo problema muitos anos antes e nos forneceram: terminação NULL!
O que é terminação NULL, você pergunta? Considere como nos exemplos acima, CR (ou literalmente enter) foi o caractere de terminação principal.
Também vimos como caracteres especiais como aspas, espaços em branco e barras invertidas podem ser usados em nomes de arquivos, embora tenham funções especiais quando se trata de outras ferramentas de análise e modificação de texto Bash, como sed. Agora compare isso com a opção -0 para xargs, de man xargs:
Os itens
-0, – nullInput terminam com um caractere nulo em vez de um espaço em branco e as aspas e a barra invertida não são especiais (cada caractere é interpretado literalmente). Desativa a string de fim de arquivo, que é tratada como qualquer outro argumento. Útil quando os itens de entrada podem conter espaço em branco, aspas ou barras invertidas. A opção GNU find -print0 produz uma entrada adequada para este modo.
E a opção -print0 para encontrar, de man find:
-fprint0 fileTrue; imprime o nome completo do arquivo na saída padrão, seguido por um caractere nulo (em vez do caractere de nova linha que -print usa). Isso permite que nomes de arquivo que contenham novas linhas ou outros tipos de espaço em branco sejam interpretados corretamente por programas que processam a saída de localização. Esta opção corresponde à opção -0 de xargs.
O verdadeiro; aqui significa que se a opção for especificada, o seguinte é verdadeiro ;. Também interessante são os dois avisos claros dados em outro lugar na mesma página do manual:
- Se você está canalizando a saída de find para outro programa e existe a menor possibilidade de que os arquivos que você está procurando possam conter uma nova linha, então você deve considerar seriamente o uso da opção -print0 em vez de -print . Consulte a seção NOMES DE ARQUIVOS INCOMUNS para obter informações sobre como os caracteres incomuns em nomes de arquivo são tratados.
- Se estiver usando find em um script ou em uma situação onde os arquivos correspondentes podem ter nomes arbitrários, você deve considerar o uso de -print0 em vez de -print.
Esses avisos claros nos lembram que analisar nomes de arquivos em bash pode ser, e é, um negócio complicado. No entanto, com as opções corretas para encontrar, a saber -print0 e xargs, a saber -0, todos os nossos caracteres especiais contendo nomes de arquivos podem ser analisados corretamente:
ls find. -name 'a *' -print0 find. -name 'a *' -print0 | xargs -0 ls find. -name 'a *' -print0 | xargs -0 rm

Primeiro, verificamos nossa lista de diretórios. Todos os nossos nomes de arquivo contendo caracteres especiais estão lá. Em seguida, fazemos um simples find ... -print0 para ver a saída. Notamos que as strings são terminadas em NULL (com o NULL ou \ 0 – o mesmo caractere – não visível).
Também observamos que há um único CR na saída, que corresponde ao único CR que introduzimos no primeiro nome de arquivo, composto de a seguido por enter seguido por b.
Finalmente, a saída não introduz uma nova linha (também contendo CR) antes de retornar o prompt $ terminal, já que as strings eram NULL e não terminadas com CR. Pressionamos enter no prompt $ terminal para tornar as coisas um pouco mais claras.
Em seguida, adicionamos xargs com as opções -0, o que permite que xargs manipule a entrada terminada em NULL corretamente. Vemos que a entrada passada e recebida de ls parece clara e não há alteração da transformação do texto acontecendo.
Finalmente, tentamos novamente nosso comando rm, e desta vez para todos os arquivos, incluindo o original contendo o CR com o qual tivemos problemas. O rm funciona perfeitamente e nenhum erro ou problema de análise é observado. Ótimo!
Concluindo
Vimos como é importante, em muitos casos, analisar e manipular corretamente os nomes dos arquivos no Bash. Embora aprender a usar find corretamente seja um pouco mais desafiador do que simplesmente usar ls, os benefícios que ele oferece podem compensar no final. Maior segurança e sem problemas com caracteres especiais.
Se gostou deste artigo, você também pode querer ler Como renomear arquivos em massa para nomes de arquivo numéricos no Linux, que mostra um interessante e complexo find -print0 | Instrução xargs -0. Aproveite!
Nenhum comentário