2010-04-09 24 views
63
sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename 

Espero que este script sed inserte una pestaña en la fuente de cada línea en $filename, pero no es así. Por alguna razón, está insertando una t en su lugar ... Extraño ...¿Por qué sed no reconoce t como una pestaña?

+1

Como SED puede variar entre plataformas (en particular, BSD/MacOSX frente Linux), puede ser útil especifica la plataforma en la que estás usando sed. – Isaac

+0

@Isaac, esto fue en Solaris – sixtyfootersdude

+0

sed "s/\ (. * \)/# \ 1 /" $ filename | tr '#' '\ t'> $ sedTmpFile && mv $ sedTmpFile $ nombre de archivo. – user2432405

Respuesta

80

No todas las versiones de sed comprenden \t. Simplemente inserte una pestaña literal en su lugar (presione Ctrl - V luego Pestaña).

+2

Ah sí; para aclarar: no todas las versiones de sed entienden '\ t' en la parte de reemplazo de la expresión (reconoció' \ t' en la parte correspondiente del patrón) –

+1

awwwwwwwwwwwwwwwwwww, vale, eso es bastante interesante. Y extraño. ¿Por qué harías que lo reconociera en un lugar pero no en el otro ...? – sixtyfootersdude

+2

Llamado desde un script, eso no funcionará: sh ignorará las pestañas. Por ejemplo, el código siguiente desde un script de shell añadirá $ TEXT_TO_ADD, sin anteponiendo por una tabulación: Sed "$ {línea} \\ un \t $ TEXT_TO_ADD " $ FILE . – Dereckson

0

sed no es compatible con \t, ni otras secuencias de escape como \n para el caso. La única forma que he encontrado para hacerlo fue insertar el carácter de tabulación en el script usando sed.

Dicho esto, es posible que desee considerar el uso de Perl o Python. Aquí hay un script Python corto que escribí que utilizo para todos regex'ing corriente:

#!/usr/bin/env python 
import sys 
import re 

def main(args): 
    if len(args) < 2: 
    print >> sys.stderr, 'Usage: <search-pattern> <replace-expr>' 
    raise SystemExit 

    p = re.compile(args[0], re.MULTILINE | re.DOTALL) 
    s = sys.stdin.read() 
    print p.sub(args[1], s), 

if __name__ == '__main__': 
    main(sys.argv[1:]) 
+2

Y la versión de Perl sería el shell de una sola línea "perl -pe 's/a/b /' filename" o " algo | perl -pe 's/a/b /' " – tiftik

+0

Agradable, eso es mucho mejor :-) –

2

No es necesario utilizar sed hacer un cambio cuando en realidad, lo que desea insertar una tabulación delante de la linea La sustitución de este caso es una operación costosa en comparación con solo imprimirla, especialmente cuando se trabaja con archivos grandes. Es más fácil de leer también, ya que no es regex.

por ejemplo, usando awk

awk '{print "\t"$0}' $filename > temp && mv temp $filename 
32

Usando Bash puede insertar un carácter de tabulación programación de este modo:

TAB=$'\t' 
echo 'line' | sed "s/.*/${TAB}&/g" 
echo 'line' | sed 's/.*/'"${TAB}"'&/g' # use of Bash string concatenation 
+0

Esto es muy útil. – Cheeso

+0

Estabas en el camino correcto con '$ 'string'' pero carecía de explicación. De hecho, sospecho que, debido al uso extremadamente incómodo, es probable que tengas una comprensión incompleta (como la mayoría de nosotros lo hacemos con bash). Consulte mi explicación a continuación: http://stackoverflow.com/a/43190120/117471 –

6

que he usado algo como esto con un intérprete de comandos en Ubuntu 12.04 (LTS) :

para añadir una nueva línea con pestaña, segundo cuando primera se corresponde:

sed -i '/first/a \\t second' filename 

Para reemplazar primera con pestaña, segundo:

sed -i 's/first/\\t second/g' filename 
+3

El doble escape es clave, es decir, use '\\ t' y no' \ t'. – zamnuts

4

Uso $(echo '\t'). Necesitará cotizaciones alrededor del patrón.

Por ejemplo. Para eliminar una ficha:

sed "s/$(echo '\t')//" 
+3

Es curioso que esté utilizando una función específica "eco de GNU" (interpretando \ t como un carácter de tabulación) para resolver un error específico de "BSD sed" (interpretando \ t como 2 caracteres separados). Presumiblemente, si tiene "eco GNU", también tendría "GNU sed". En ese caso, no necesitarías usar echo. Con BSD, echo 'echo '\ t'' va a generar 2 caracteres separados. La forma portátil POSIX es usar 'printf '\ t''. Es por eso que digo: no trates de hacer que tu código sea portátil al no usar bash. Es más difícil de lo que piensas Usar 'bash' es la cosa más portátil que la mayoría de nosotros puede hacer. –

4

@sedit estaba en el camino correcto, pero es un poco incómodo para definir una variable.

Solución (bash específica)

La manera de hacer esto en bash es el uso de poner un signo de dólar en frente de la cadena de comillas simples.

$ echo -e '1\n2\n3' 
1 
2 
3 

$ echo -e '1\n2\n3' | sed 's/.*/\t&/g' 
t1 
t2 
t3 

$ echo -e '1\n2\n3' | sed $'s/.*/\t&/g' 
    1 
    2 
    3 

Si la cadena tiene que incluir la expansión de variables, se puede, pero citado cadenas juntas de esta manera:

$ timestamp=$(date +%s) 
$ echo -e '1\n2\n3' | sed "s/.*/$timestamp"$'\t&/g' 
1491237958 1 
1491237958 2 
1491237958 3 

Explicación

En bash $'string' causas "expansión ANSI-C". Y eso es lo que la mayoría de nosotros esperamos cuando usamos cosas como \t, \r, \n, etc. Desde: https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html#ANSI_002dC-Quoting

palabras de la forma $ 'cadena' se trata especialmente. La palabra se expande a cadena, con caracteres de escama invertida reemplazados según lo especificado por el estándar ANSI C. Las secuencias de escape de barra invertida, si están presentes, son decodificadas ...

El resultado ampliado es una comilla simple, como si el signo de dólar no tuviera estado presente.

solución (si se debe evitar bash)

personalmente que la mayoría de los esfuerzos para evitar fiesta son tontos porque evitando bash NO * hacer que su código portable. (Tu código será menos frágil si lo cambias a bash -eu que si tratas de evitar bash y usas sh [a menos que seas un ninja POSIX absoluto].) Pero en lugar de tener un argumento religioso sobre eso, solo te daré la MEJOR * respuesta.

$ echo -e '1\n2\n3' | sed "s/.*/$(printf '\t')&/g" 
    1 
    2 
    3 

* ¿RESPUESTA METIL? Sí, porque un ejemplo de lo que la mayoría de los scripters de shell anti-bash harían mal en su código es usar echo '\t' como en @robrecord's answer. Eso funcionará para eco de GNU, pero no para eco de BSD. Esto se explica por The Open Group en http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16

+0

La mejor solución, loco, no tiene más votos ascendentes. – scx

0

En lugar de BSD sed, yo uso Perl:

[email protected]:~$ python -c "print('\t\t\thi')" |perl -0777pe "s/\t/ /g" 
    hi 
Cuestiones relacionadas