sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
Espero que este sed
script inserte un tab
delante de cada línea, $filename
pero no es así. Por alguna razón, está insertando un t
.
sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
Espero que este sed
script inserte un tab
delante de cada línea, $filename
pero no es así. Por alguna razón, está insertando un t
.
Respuestas:
No todas las versiones de sed
entender \t
. Simplemente inserte una pestaña literal en su lugar (presione Ctrl- Vluego Tab).
\t
en la parte de reemplazo de la expresión (reconoció \t
en la parte de coincidencia de patrones muy bien)
Usando Bash, puede insertar un carácter TAB programáticamente así:
TAB=$'\t'
echo 'line' | sed "s/.*/${TAB}&/g"
echo 'line' | sed 's/.*/'"${TAB}"'&/g' # use of Bash string concatenation
$'string'
pero falta explicación. De hecho, sospecho que debido al uso extremadamente incómodo, probablemente tenga una comprensión incompleta (como la mayoría de nosotros lo hacemos con bash). Vea mi explicación a continuación: stackoverflow.com/a/43190120/117471
$TAB
dentro de comillas simples, por lo que deberá usarlo entre comillas dobles.
*
comillas dobles internas ... esto se tratará como un glob, no como la expresión regular que desea.
@sedit estaba en el camino correcto, pero es un poco incómodo definir una variable.
La forma de hacer esto en bash es poner un signo de dólar delante de su cadena entre comillas.
$ 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 su cadena necesita incluir expansión variable, puede juntar cadenas entre comillas así:
$ timestamp=$(date +%s)
$ echo -e '1\n2\n3' | sed "s/.*/$timestamp"$'\t&/g'
1491237958 1
1491237958 2
1491237958 3
En bash $'string'
provoca "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
Las palabras de la forma $ 'cadena' se tratan especialmente. La palabra se expande a una cadena , y los caracteres de escape con barra invertida se reemplazan según lo especificado por el estándar ANSI C. Las secuencias de escape de barra invertida, si están presentes, se decodifican ...
El resultado expandido es de comillas simples, como si el signo de dólar no hubiera estado presente.
Personalmente, creo que la mayoría de los esfuerzos para evitar bash son tontos porque evitar bashisms NO * hace que su código sea portátil. (Su código será menos frágil si lo manipula bash -eu
que si intenta evitar bash y usa sh
[a menos que sea un ninja absoluto de POSIX]). Pero en lugar de tener un argumento religioso al respecto, le daré lo MEJOR * responder.
$ echo -e '1\n2\n3' | sed "s/.*/$(printf '\t')&/g"
1
2
3
* ¿La mejor respuesta? 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 usarlo echo '\t'
como en la respuesta de @ robrecord . Eso funcionará para el eco de GNU, pero no para el eco de BSD. Eso lo explica The Open Group en http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16 Y este es un ejemplo de por qué tratar de evitar los bashismos generalmente falla.
He usado algo como esto con un shell Bash en Ubuntu 12.04 (LTS):
Para agregar una nueva línea con tabulación, la segunda cuando la primera coincide:
sed -i '/first/a \\t second' filename
Para reemplazar primero con tabulador, segundo :
sed -i 's/first/\\t second/g' filename
\\t
y no \t
.
Utilice $(echo '\t')
. Necesitará comillas alrededor del patrón.
P.ej. Para eliminar una pestaña:
sed "s/$(echo '\t')//"
echo '\t'
generará 2 caracteres separados. La forma portátil POSIX es usar printf '\t'
. Por eso digo: No intente hacer que su código sea portátil sin usar bash. Es más difícil de lo que piensas. Usar bash
es lo más portátil que la mayoría de nosotros podemos hacer.
No necesita usar sed
para hacer una sustitución cuando, en realidad, solo desea insertar una pestaña al frente de la línea. La sustitución de este caso es una operación costosa en comparación con simplemente imprimirlo, especialmente cuando se trabaja con archivos grandes. También es más fácil de leer ya que no es regex.
por ejemplo, usando awk
awk '{print "\t"$0}' $filename > temp && mv temp $filename
sed
no admite \t
, ni otras secuencias de escape como \n
para el caso. La única forma que encontré 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 breve script de Python que escribí y que uso para todas las expresiones regulares de transmisión:
#!/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:])
En lugar de BSD sed, uso perl:
ct@MBA45:~$ python -c "print('\t\t\thi')" |perl -0777pe "s/\t/ /g"
hi
Creo que otros han aclarado esta adecuadas para determinar otros enfoques ( sed
, AWK
, etc.). Sin embargo, bash
siguen mis respuestas específicas (probadas en macOS High Sierra y CentOS 6/7).
1) Si OP quisiera usar un método de búsqueda y reemplazo similar al que propusieron originalmente, sugeriría usarlo perl
para esto, de la siguiente manera. Notas: las barras invertidas antes de los paréntesis para expresiones regulares no deberían ser necesarias, y esta línea de código refleja cómo $1
es mejor usarla que \1
con el perl
operador de sustitución (por ejemplo, según la documentación de Perl 5 ).
perl -pe 's/(.*)/\t$1/' $filename > $sedTmpFile && mv $sedTmpFile $filename
2) Sin embargo, como lo señaló ghostdog74 , dado que la operación deseada es simplemente agregar una pestaña al comienzo de cada línea antes de cambiar el archivo tmp al archivo de entrada / destino ( $filename
), lo recomendaría perl
nuevamente pero con la siguiente modificación (s):
perl -pe 's/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
## OR
perl -pe $'s/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
3) Por supuesto, el archivo tmp es superfluo , por lo que es mejor hacer todo 'en su lugar' (agregando -i
bandera) y simplificar las cosas a una línea más elegante con
perl -i -pe $'s/^/\t/' $filename