A resposta mais simples e mais portátil é executar o seguinte:
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
my @dirs = (@ARGV == 0) ? <*> : @ARGV;
find sub {
next unless -f && -T;
system('perl', '-i', '-pe', 's/[\t\xA0 ]+$//', $File::Find::name);
} => @dirs;
Explico por que abaixo, onde também mostro como fazê-lo usando apenas a linha de comando e como lidar com arquivos de texto trans-ASCII como ISO-8859-1 (Latin-1) e UTF-8, que depois não possuem -ASCII em branco neles.
O resto da história
O problema é que o find (1) não suporta o -T
operador de teste de arquivo nem reconhece as codificações - caso necessário - o que é absolutamente necessário para detectar a codificação Unicode padrão de fato UTF-8.
O que você pode fazer é executar a lista de nomes de arquivos através de uma camada que gera arquivos binários. Por exemplo
$ find . -type f | perl -nle 'print if -T' | xargs sed -i 's/[ \t]*$//'
No entanto, agora você tem problemas com espaço em branco nos seus nomes de arquivos, portanto, é necessário atrasá-lo com terminação nula:
$ find . -type f -print0 | perl -0 -nle 'print if -T' | xargs -0 sed -i 's/[ \t]*$//'
Outra coisa que você poderia fazer é usar não , find
mas find2perl
já que Perl -T
já entende :
$ find2perl * -type T -exec sed 's/[ \t]*$//' -i {} \; | perl
E se você quiser que o Perl assuma que seus arquivos estão em UTF-8, use
$ find2perl * -type T -exec sed 's/[ \t]*$//' -i {} \; | perl -CSD
Ou você pode salvar o script resultante em um arquivo e editá-lo. Você realmente não deve apenas executar o -T
teste de arquivo em qualquer arquivo antigo, mas apenas naqueles que são arquivos simples, conforme determinado pela primeira vez -f
. Caso contrário, você corre o risco de abrir promoções do dispositivo, bloquear fifos etc.
No entanto, se você fizer tudo isso, poderá ignorar completamente o sed (1). Por um lado, é mais portátil, pois a versão POSIX do sed (1) não entende -i
, enquanto todas as versões do Perl o fazem. As versões dos últimos dias do sed apropriadamente se apropriaram da -i
opção muito útil do Perl, onde ti aparece pela primeira vez.
Isso também oferece a oportunidade de corrigir seu regex também. Você realmente deve usar um padrão que corresponda a um ou mais espaços em branco horizontais à direita, não apenas a zero, ou será mais lento se copiar desnecessariamente. Ou seja, isso:
s/[ \t]*$//
deveria estar
s/[ \t]+$//
No entanto, como fazer com que o sed (1) entenda que requer uma extensão não POSIX, geralmente -R
para os System Ⅴ Unices como Solaris ou Linux, ou -E
para os BSD como OpenBSD ou MacOS. Eu suspeito que é impossível no AIX. É quase mais fácil escrever um shell portátil do que um script de shell portátil, você sabe.
Aviso em 0xA0
Embora esses sejam os únicos caracteres de espaço em branco horizontal no ASCII, tanto o ISO-8859-1 quanto o Unicode também possuem o NO-BREAK SPACE no ponto de código U + 00A0. Esse é um dos dois principais caracteres não ASCII encontrados em muitos corpora Unicode e, ultimamente, tenho visto muitas pessoas quebrando o código regex porque se esqueceram disso.
Então, por que você não faz isso:
$ find * -print0 | perl -0 -nle 'print if -f && -T' | xargs -0 perl -i -pe 's/[\t\xA0 ]+$//'
Se você pode ter arquivos UTF-8 para lidar com, add -CSD
, e se você estiver executando Perl V5.10 ou superior, você pode usar \h
para o espaço em branco horizontal e \R
por uma quebra de linha genérica, que inclui \r
, \n
, \r\n
, \f
, \cK
, \x{2028}
, e \x{2029}
:
$ find * -print0 | perl -0 -nle 'print if -f && -T' | xargs -0 perl -CSD -i -pe 's/\h+(?=\R*$)//'
Isso funcionará em todos os arquivos UTF-8, independentemente de quebras de linha, eliminando o espaço em branco horizontal à direita (propriedade de caractere Unicode HorizSpace
), incluindo o incômodo NO-BREAK SPACE que ocorre antes de uma quebra de linha Unicode (incluindo combos de CRLF) no final de cada linha.
Também é muito mais portátil que a versão sed (1), porque há apenas uma implementação perl (1), mas muitas da sed (1).
O principal problema que vejo ainda existe com o find (1), já que em alguns sistemas verdadeiramente recalcitrantes (você sabe quem você é, AIX e Solaris), ele não entende a -print0
diretiva supercrítica . Se essa é a sua situação, você deve apenas usar o File::Find
módulo diretamente do Perl e não usar outros utilitários Unix. Aqui está uma versão Perl pura do seu código que não depende de mais nada:
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
my @dirs = (@ARGV == 0) ? <*> : @ARGV;
find sub {
next unless -f && -T;
system('perl', '-i', '-pe', 's/[\t\xA0 ]+$//', $File::Find::name);
} => @dirs;
Se você estiver executando apenas arquivos de texto ASCII ou ISO-8859-1, tudo bem, mas se estiver executando com arquivos ASCII ou UTF-8, adicione -CSD
aos comutadores na chamada interna para Perl.
Se você tiver codificações mistas dos três ASCII, ISO-8859-1 e UTF-8, receio que você tenha outro problema. :( Você precisará descobrir a codificação por arquivo e nunca há uma boa maneira de adivinhar isso.
Espaço em branco Unicode
Para o registro, o Unicode possui 26 caracteres de espaço em branco diferentes. Você pode usar o utilitário unichars para detectá -los. Somente os três primeiros caracteres de espaço em branco horizontal são quase sempre vistos:
$ unichars '\h'
---- U+0009 CHARACTER TABULATION
---- U+0020 SPACE
---- U+00A0 NO-BREAK SPACE
---- U+1680 OGHAM SPACE MARK
---- U+180E MONGOLIAN VOWEL SEPARATOR
---- U+2000 EN QUAD
---- U+2001 EM QUAD
---- U+2002 EN SPACE
---- U+2003 EM SPACE
---- U+2004 THREE-PER-EM SPACE
---- U+2005 FOUR-PER-EM SPACE
---- U+2006 SIX-PER-EM SPACE
---- U+2007 FIGURE SPACE
---- U+2008 PUNCTUATION SPACE
---- U+2009 THIN SPACE
---- U+200A HAIR SPACE
---- U+202F NARROW NO-BREAK SPACE
---- U+205F MEDIUM MATHEMATICAL SPACE
---- U+3000 IDEOGRAPHIC SPACE
$ unichars '\v'
---- U+000A LINE FEED (LF)
---- U+000B LINE TABULATION
---- U+000C FORM FEED (FF)
---- U+000D CARRIAGE RETURN (CR)
---- U+0085 NEXT LINE (NEL)
---- U+2028 LINE SEPARATOR
---- U+2029 PARAGRAPH SEPARATOR