Necesito reemplazar algunos caracteres no imprimibles con espacios en el archivo.
Específicamente, todos los caracteres de 0x00
hasta 0x1F
, excepto 0x09
(TAB), 0x0A
(nueva línea), 0x0D
(CR)
Hasta ahora, solo necesitaba reemplazar el 0x00
personaje. Como mi sistema operativo anterior era AIX (sin comandos GNU), no puedo usar sed
(bueno, puedo pero tenía algunas limitaciones). Entonces, encontré el siguiente comando usando perl
, que funcionó como se esperaba:
perl -p -e 's/\x0/ /g' $FILE_IN > $FILE_OUT
Ahora estoy trabajando en Linux, así que esperaba poder usar el sed
comando.
Mis preguntas:
¿Es este comando apropiado para reemplazar esos caracteres? Lo intenté y parece funcionar, pero quiero asegurarme de que:
perl -p -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT
Pensé que
perl -p
funciona comosed
. Entonces, ¿por qué funciona el comando anterior (al menos, no falla) y el siguiente no?sed -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT
Me dice:
sed: -e expresión # 1, char 34: Carácter de intercalación no válido
perl -p
imprime el producto final destdin
después de hacer las operaciones que desea, en este caso es solo reemplazo.sed
La expresión regular podría ser diferente aperl
.Respuestas:
Ese es un trabajo típico para
tr
:En su caso, no funciona
sed
porque está en una ubicación donde esos rangos no tienen sentido. Si desea trabajar con valores de bytes en lugar de caracteres y donde el orden se basa en el valor numérico de esos bytes, lo mejor es utilizar la configuración regional C . Su código habría funcionado conLC_ALL=C
GNUsed
, pero usarsed
(y mucho menosperl
) es un poco excesivo aquí (y esos\xXX
no son portátiles en lassed
implementaciones, mientras que estetr
enfoque es POSIX).También puede confiar en la idea de su localidad de los caracteres imprimibles con:
Pero con GNU
tr
(como se encuentra típicamente en los sistemas basados en Linux), eso solo funciona en entornos locales donde los caracteres son de un solo byte (por lo general, no UTF-8).En la configuración regional de C, eso también excluiría DEL (0x7f) y todos los valores de bytes anteriores (no en ASCII).
En las configuraciones regionales UTF-8, puede usar GNU
sed
que no tiene el problema que GNUtr
tiene:(nota que aquellos
\r
,\t
no son estándar, y GNUsed
no los reconoce siPOSIXLY_CORRECT
está en el medio ambiente (se tratarlos como barra invertida, r y t ser parte del conjunto como requiere POSIX)).Sin embargo, no convertiría bytes que no forman caracteres válidos si los hubiera.
fuente
tr
hace el comando. Yo entiendo (más o menos) lo queLC_ALL = C
es, pero no todos juntos. Sin embargo,tr -d
elimina esos caracteres, pero quiero reemplazarlos con espacios. Lo siento, el título estaba mal. Me acabo de dar cuenta, cuando @don_crissti modificó.XCOM
. Por ejemplo, los caracteres no ASCII comoÉ
se codifican (usandood -xa
) como0xC9
, así que supongo que lo seríaISO-8859-1
.locale -a
para ver si hay configuraciones regionales con iso8859-1 como el conjunto de caracteres en su sistema y usarLC_CTYPE=<that-locale> tr ...[:print:]...
para convertir no imprimibles en esa configuración regional. O puede usar iconv para convertir esos archivos al conjunto de caracteres de su localidad.LC_ALL=en_US.iso88591
. Entonces, su comando (tr -c '[:print:]\t\r\n' '[ *]'
) funciona perfectamente sin modificar la configuración regional o la conversión de archivos. Muchas gracias.Intenté enviar una notificación a través de libnotify, con contenido que puede contener caracteres no imprimibles. Las soluciones existentes no me funcionaron del todo (usando una lista blanca de caracteres usando
tr
Works, pero elimina cualquier carácter de varios bytes).Esto es lo que funcionó, mientras pasaba la prueba 💩:
fuente