La respuesta más simple y portátil es ejecutar esto:
#!/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 qué a continuación, donde también muestro cómo hacerlo usando solo la línea de comando, así como también cómo tratar con archivos de texto trans-ASCII como ISO-8859-1 (Latin-1) y UTF-8, que a menudo tienen - Espacio en blanco ASCII en ellos.
El resto de la historia
El problema es que find (1) no es compatible con el -T
operador de prueba de archivo, ni reconoce las codificaciones si lo hiciera, lo cual es absolutamente necesario para detectar la codificación Unicode estándar de facto UTF-8.
Lo que podría hacer es ejecutar la lista de nombres de archivo a través de una capa que arroja archivos binarios. Por ejemplo
$ find . -type f | perl -nle 'print if -T' | xargs sed -i 's/[ \t]*$//'
Sin embargo, ahora tiene problemas con el espacio en blanco en sus nombres de archivo, por lo que debe retrasar esto con una terminación nula:
$ find . -type f -print0 | perl -0 -nle 'print if -T' | xargs -0 sed -i 's/[ \t]*$//'
Otra cosa que podría hacer es usar no find
pero find2perl
, ya que Perl -T
ya lo comprende :
$ find2perl * -type T -exec sed 's/[ \t]*$//' -i {} \; | perl
Y si desea que Perl asuma que sus archivos están en UTF-8, use
$ find2perl * -type T -exec sed 's/[ \t]*$//' -i {} \; | perl -CSD
O puede guardar el script resultante en un archivo y editarlo. Realmente no debería ejecutar la -T
prueba de archivo en cualquier archivo antiguo, sino solo en aquellos que son archivos simples según lo determinado por primera vez -f
. De lo contrario, corre el riesgo de abrir dispositivos especiales, bloqueo en fifos, etc.
Sin embargo, si va a hacer todo eso, también podría omitir sed (1) por completo. Por un lado, es más portátil, ya que la versión POSIX de sed (1) no comprende -i
, mientras que todas las versiones de Perl sí. Las versiones recientes de sed se apropiaron con amor de la -i
opción muy útil de Perl, donde aparece por primera vez.
Esto también te da la oportunidad de arreglar tu expresión regular también. Realmente debería usar un patrón que coincida con uno o más espacios en blanco horizontales finales, no solo con cero, o se ejecutará más lentamente debido a la copia innecesaria. Eso es esto:
s/[ \t]*$//
debiera ser
s/[ \t]+$//
Sin embargo, cómo lograr que sed (1) entienda que requiere una extensión que no sea POSIX, generalmente -R
para sistemas System como Solaris o Linux, o -E
para BSD como OpenBSD o MacOS. Sospecho que es imposible bajo AIX. Sabes, es más fácil escribir un shell portátil que un script de shell portátil.
Advertencia sobre 0xA0
Aunque esos son los únicos caracteres de espacio en blanco horizontales en ASCII, tanto ISO-8859-1 como en consecuencia también Unicode tienen el ESPACIO SIN INTERRUPCIONES en el punto de código U + 00A0. Este es uno de los dos principales caracteres no ASCII que se encuentran en muchos corpus Unicode, y últimamente he visto romper el código regex de muchas personas porque lo olvidaron.
Entonces, ¿por qué no haces esto?
$ find * -print0 | perl -0 -nle 'print if -f && -T' | xargs -0 perl -i -pe 's/[\t\xA0 ]+$//'
Si es posible que tenga archivos UTF-8 para hacer frente, complemento -CSD
, y si está ejecutando Perl v5.10 o superior, se puede utilizar \h
para el espacio en blanco horizontal y \R
de un salto de línea genérico, que incluye \r
, \n
, \r\n
, \f
, \cK
, \x{2028}
, y \x{2029}
:
$ find * -print0 | perl -0 -nle 'print if -f && -T' | xargs -0 perl -CSD -i -pe 's/\h+(?=\R*$)//'
Eso funcionará en todos los archivos UTF-8 sin importar sus saltos de línea, eliminando los espacios en blanco horizontales (propiedad de caracteres Unicode HorizSpace
), incluido el molesto ESPACIO NO-BREAK que ocurre antes de un salto de línea Unicode (incluye combos CRLF) al final de cada línea.
También es mucho más portátil que la versión sed (1), porque solo hay una implementación perl (1), pero muchas de sed (1).
El principal problema que veo que queda allí es con find (1), ya que en algunos sistemas verdaderamente recalcitrantes (ya sabes quién eres, AIX y Solaris), no entenderá la -print0
directiva supercrítica . Si esa es su situación, entonces debería usar el File::Find
módulo de Perl directamente y no usar otras utilidades de Unix. Aquí hay una versión pura de Perl de su código que no se basa en nada más:
#!/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;
Si solo está ejecutando archivos de texto ASCII o ISO-8859-1, está bien, pero si está ejecutando archivos ASCII o UTF-8, agréguelos -CSD
a los interruptores en la llamada interior a Perl.
Si tiene codificaciones mixtas de los tres ASCII, ISO-8859-1 y UTF-8, entonces me temo que tiene otro problema. :( Deberá averiguar la codificación por archivo, y nunca hay una buena manera de adivinar eso.
Espacio en blanco Unicode
Para el registro, Unicode tiene 26 caracteres de espacio en blanco diferentes. Puede usar la utilidad unichars para detectarlos . Solo se ven los primeros tres caracteres de espacio en blanco horizontales:
$ 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