Reemplazo simple de sed de pestañas misteriosamente fallando


44

Esto debería ser realmente simple, pero por alguna razón no está funcionando:

sed -i.bak -E 's/\t/  /' file.txt

En lugar de reemplazar caracteres de tabulación, está reemplazando tcaracteres. He probado todas las variaciones de esto que se me ocurrieron, jugando con citas, etc. Busqué en Google y encontré que todos los demás usaban expresiones bastante similares y parecen funcionar para ellos.

El -Ees una cosa de OS X. Pensé que el fracaso podría ser el resultado de una peculiaridad extraña de OS X sed, así que lo probé también con Ruby (sin el -i), y obtuve el mismo resultado:

ruby -pe '$_.gsub!(/\t/,"  ")' < file.txt > file.new

Estoy usando Bash 3.2.51 en OS X e iTerm, aunque no puedo ver cómo alguno de ellos podría ser terriblemente relevante. No he establecido ninguna variable de entorno extraña, aunque puedo publicar cualquiera que creas que puede ser relevante.

¿Qué podría estar mal?

ACTUALIZACIÓN : Debo haber hecho algún otro error tipográfico o de ortografía cuando probé la versión de Ruby, ya Gilles señala que hace el trabajo (y he nunca se tuvo que me guiaron a mal!). No estoy seguro de lo que sucedió, pero estoy bastante seguro de que debe haber sido mi error.


55
Es posible que deba tratar de reemplazar el \ten la seddeclaración con CTRL-V<TAB>dónde <TAB>está la tecla de tabulación y la CTRL-Vtecla de control y vpresionar juntas.
unxnut

Si Ruby también está obteniendo una respuesta incorrecta, entonces podría ser su biblioteca de expresiones regulares. (He probado sus dos comandos, y ambos reemplazan la pestaña con 2 espacios). Entonces, con suerte, si instala Gnu sed, también instalará la biblioteca correcta.
ctrl-alt-delor

Respuestas:


64

La sintaxis \tpara un carácter de tabulación en sed no es estándar. Ese escape es una extensión de sed de GNU . Encontrará muchos ejemplos en línea que lo usan porque mucha gente usa GNU sed (es la implementación de sed en Linux no incrustado). Pero OS X sed , como otros * BSD sed, no es compatible \tcon tab y en su lugar trata \tcomo una barra invertida seguida de t.

Hay muchas soluciones, como:

  • Use un carácter de tabulación literal.

    sed -i.bak 's/  /  /' file.txt
    
  • Use tro printfpara producir un carácter de tabulación.

    sed -i.bak "s/$(printf '\t')/  /" file.txt
    sed -i.bak "s/$(echo a | tr 'a' '\t')/  /" file.txt
    
  • Utilice la sintaxis de cadena de bash para permitir escapes de barra invertida .

    sed -i.bak $'s/\t/  /' file.txt
    
  • Utiliza Perl, Python o Ruby. El fragmento de Ruby que publicaste funciona.


Para los scripts sed que están contenidos en un ...sedscript (utilizado mediante la -fopción), los caracteres de tabulación literal me parecen la única posibilidad. Al editar esto con vim, set noexpandtabes importante.
Tobias

Advertencia: solo use esa técnica de "carácter de tabulación literal" si desea que su compañero de trabajo regrese detrás de usted y rompa su script más tarde. Solo usa esa trtécnica si quieres que tu compañero de trabajo te apuñale en la cara cuando leen tu guión.
Bruno Bronosky

¿Está la segunda comilla doble fuera de lugar en el segundo bloque de código? Tuve que moverlo a donde está actualmente la comilla simple de cierre.
Ellen Spertus

Gracias por el enlace a la sintaxis de la cadena bash ... No tenía idea (y esta es la mejor opción, en mi humilde opinión).
Levigroker

sed $'s/<regex>/\t/' file.txtfunciona para insertar, pero $parece romper mi script cuando trato de incluir parte de la expresión regular en mi sustitución, es decir, sed $'s,\(ontology/[0-9]\+\),\t\txxx\1xxx\t\t,'da `xxxxxx` con mi valor de coincidencia esperado reemplazado por ``. ¿Hay un equivalente a \1cuando se usa la sintaxis de cadena de bash? Editar: se supone que hay un carácter unicode U + 231C en el medio de xxx <U + 231C> xxx.
Josh

14

Use una cita específica de Bash que le permite usar cadenas como en C, de modo que se pase un carácter de tabulación real a sed, no una secuencia de escape:

sed -i.bak -E $'s/\t/  /' file.txt

1
También llamado "ANSI-C" citando si otros quieren buscar más información al respecto.
wisbucky

2
Parece funcionar en cualquier shell bourne, también funciona en UNIX que no son bash. Sin embargo, no funciona en variantes csh.
jornane

3
sed -i $'s/\t/  /g' file.txt 

funciona para mí en OS X y es el mismo comando que uso en Linux todo el tiempo.


Tenga en cuenta que esto reemplaza todas las pestañas en cada fila, mientras que el OP tiene la intención de reemplazar solo la primera (a juzgar por el comando que usan).
Kusalananda

1

Como se señaló, no todas las sedimplementaciones admiten la notación \tcomo una pestaña horizontal.

Puede lograr fácilmente su sustitución con:

 perl -pi.old -e 's{\t+}{ }g' file.txt

Esto realiza un reemplazo in situ que conserva su archivo original como "* .old". Perl permite delimitadores alternativos para el clásico /haciendo que la expresión sea mucho más legible (es decir, sin el síndrome del "palillo de dientes inclinado").

El +dice una o más repeticiones de un carácter de tabulación van a ser sustituidos. El gmodificador permite reemplazos globales a lo largo del final de cada línea.


0

También puedes usar echodentro sed:

sed -i "s/$(echo '\t')//g"


Tenga en cuenta que echo '\t'solo se generará \ten la implementación de algunos shells de echo.
Kusalananda

0

Si desea una versión más potente sed(compatible \ty más) que la de OS X, instale GNU sed .


Como tampoco funcionó con Ruby, no estoy seguro de por qué concluiría que OS X sedes el problema. ¿Tienes alguna razón para creer que ese es el problema? Me encantaría instalar GNU sed si tuviera motivos para creer que resolvería el problema, pero parece que lo he descartado.
iconoclasta

Con Ruby, tendrás que usar solo una barra invertida:ruby -pe '$_.gsub!(/\t/," ")' < file.txt
vinc17

0

Si está bien requerirlo basho zshcomo un shell, entonces esta es la solución más fácil que se me ocurre:

sed "s/$(echo -n -e "\t")/ /" file.txt

Sin embargo, tenga en cuenta que los echoindicadores ( -ny -e) no están definidos en POSIX, por lo que un shell de conformidad POSIX no requiere comprender estos indicadores, pero muchos lo harán por razones de compatibilidad.


-1

Me sorprende que nadie sugiriera la solución muy simple de: sed -i.bak -E 's/\\\t/ /' file.txt Eso debería funcionar.

Debe escapar del escape (de ahí los 3 \ s) para permitir que sed comprenda que está tratando de usar un carácter \ t en la expresión regular cuando todo está sustituido ...


¿Por qué tres barras invertidas específicamente?
Michael Homer

3
Si uso GNU sed, uno \ es suficiente, ya que no es necesario escapar. El problema es que BSD sedno admite esta sintaxis para pestañas.
iconoclasta

No funciona en mi El Capitan.
Franklin Yu

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.