¿Cómo insertar una barra invertida y una nueva línea antes de un patrón?

¿Cómo insertar una barra invertida y una nueva línea antes de un patrón?

Quería capturar \n en una variable (supongamos a) y sustituir $a delante del patrón de búsqueda en un archivo (abc.txt)

¿Alguien puede sugerirme la solución?

> cat abc.txt
hi how are you how is your health
> echo $a
\

resultado esperado (patrón de búsqueda - how)

hi \
how are you \
how is your health

Respuesta1

En un shell tipo Bourne o rc

a='
' perl -pe 's/pattern/$ENV{a}$&/g' < abc.txt

pasaría una avariable de entorno que perlcontiene un carácter de nueva línea e perlinsertaría el contenido de esa variable antes de cada aparición de patternen el contenido de abc.txt.

Para asignar cualquier carácter xque no sea 'una variable en shells tipo Bourne, puede usar:

a='x'

Entonces, para barra invertida:

a='\'

Para nueva línea:

a='
'

Para caracteres de control como nueva línea, pero eso sería aún peor para retroceso o retorno de carro, por ejemplo, eso hace que el código sea menos legible.

ksh93 introdujo una nueva $'...'forma de comillas para especificar esos caracteres en forma de escape. Otros shells como bash, zsho mkshFreeBSD shlo han copiado y ampliado (como el $'\uXXXX'formulario agregado por zsh) desde entonces.

En esos shells, puedes usar:

a=$'\n' a=$'\b' a=$'\r' a=$'\\' a=$'\''

Para asignar una nueva línea, un retroceso, un retorno de carro, una barra invertida o una comilla simple.

Ese operador de cotización aún no es estándar, por lo que no puede usarlo en un shscript portátil. Una alternativa estándar es utilizar:

a=$(printf '\b')

para retroceso, por ejemplo, pero eso no funciona para nueva línea, ya que la sustitución de comandos ( $(cmd)) elimina los caracteres de nueva línea finales de la salida de cmd. Hay que recurrir a trucos como:

nl=$(printf '\n.'); nl=${nl%.}

(es decir, agregue un .y elimínelo después) para conservarlo.

Ten en cuenta que perltambién entiende esas \nnotaciones en su código, por lo que puedes hacer:

perl -pe 's/pattern/\n$&/g' < abc.txt

La implementación GNU de sed(y algunas otras hoy en día) también lo admite:

sed 's/pattern/\n&/g' < abc.txt

pero eso no es estándar. Estándar, una nueva línea en la parte de reemplazo del scomando seddebe expresarse con una barra invertida seguida de una nueva línea, por lo que sería:

backslash='\' newline='
'
sed "s/pattern/$backslash$newline&/g" < abc.txt

O sin las variables:

sed 's/pattern/\
&/g' < abc.txt

Entonces, si desea insertar una barra invertida y una nueva línea delante de pattern, necesita:

sed 's/pattern/\\\
&/g' < abc.txt

3 barras invertidas en total, dos para una barra invertida literal y una para la nueva línea. O con perl:

perl -pe 's/pattern/\\\n$&/g' < abc.txt

O con tu avariable:

a='\
' perl -pe 's/pattern/$ENV{a}$&/g' < abc.txt

Respuesta2

También puedes usar los propios comandos de bash usando:

cat abc.txt | sed -e 's/how/\nhow/g' |  while read line; do echo "$line \\"; done

información relacionada