Tengo un archivo de texto con el siguiente formato:
keyword value
keyword value
...
Donde la palabra clave es una sola palabra y el valor es todo lo demás hasta el final de la línea. Quiero leer el archivo desde un script de shell, de manera que los valores (pero no las palabras clave) experimenten una expansión de shell.
Con sed es fácil hacer coincidir las palabras clave y las partes de valor
input='
keyword value value
keyword "value value"
keyword `uname`
'
echo "$input"|sed -e 's/^\([^[:space:]]*\)[[:space:]]\(.*\)$/k=<\1> v=<\2>/'
que produce
k=<keyword> v=<value value>
k=<keyword> v=<"value value">
k=<keyword> v=<`uname`>
pero la pregunta es cómo puedo incrustar un comando de shell en la parte de reemplazo de la expresión sed. En este caso, me gustaría que fuera el reemplazo \1 `echo \2`
.
Respuestas:
El sed estándar no puede llamar a un shell ( GNU sed tiene una extensión para hacerlo , si solo le importa Linux no incrustado), por lo que tendrá que hacer parte del procesamiento fuera de sed. Hay varias soluciones; todo requiere una cita cuidadosa.
No está claro exactamente cómo desea que se expandan los valores. Por ejemplo, si una línea es
¿Cuál de los siguientes debe ser el resultado?
Discutiré varias posibilidades a continuación.
cáscara pura
Puede hacer que el shell lea la entrada línea por línea y la procese. Esta es la solución más simple, y también la más rápida para archivos cortos. Esto es lo más cercano a su requerimiento "
echo \2
":read -r keyword value
se establece$keyword
en la primera palabra delimitada por espacios en blanco de la línea y$value
en el resto de la línea menos los espacios en blanco finales.Si desea expandir referencias de variables, pero no ejecutar comandos fuera de las sustituciones de comandos, coloque
$value
dentro de un documento aquí . Sospecho que esto es lo que realmente estabas buscando.sed entubado en una concha
Puede transformar la entrada en un script de shell y evaluar eso. Sed está preparado para la tarea, aunque no es tan fácil. De acuerdo con su
echo \2
requisito " " (tenga en cuenta que debemos escapar de las comillas simples en la palabra clave):Al ir con un documento aquí, todavía necesitamos escapar de la palabra clave (pero de manera diferente).
Este es el método más rápido si tiene muchos datos: no inicia un proceso separado para cada línea.
awk
Las mismas técnicas que utilizamos con sed funcionan con awk. El programa resultante es considerablemente más legible. Yendo con "
echo \2
":Usando un documento aquí:
fuente
Tener GNU
sed
puede usar el siguiente comando:Qué salidas:
con sus datos de entrada.
Explicación:
El comando sed suprime la salida regular usando la
-n
opción-r
se pasa a usar expresiones regulares extendidas que nos ahorra algunos escapes de caracteres especiales en el patrón, pero no es obligatorio.El
s
comando se usa para transferir la línea de entrada al comando:La palabra clave get ha citado el valor no. Le paso la opción
e
, que es específica de GNU, als
comando, que le dice a sed que ejecute el resultado de la sustitución como un comando de shell y lea los resultados en el búfer de patrón (incluso varias líneas). El uso de la opciónp
después de (!)e
Hace que sesed
imprima el búfer de patrón después de que se haya ejecutado el comando.fuente
-n
yp
, es decirsed -r 's/([^ ]+) (.*)/echo "\1" \2\n/e' input
. Pero gracias por esto! No sabía sobre lae
opción.e
opción (introducida por GNU). ¿Eso sigue siendosed
? :)Podrías probar este enfoque:
(si entiendo bien tu intención). Es decir, inserte el "proceso" al comienzo de cada línea no vacía para convertirlo en un script como:
para ser evaluado (
eval
) donde proceso es una función que imprime el mensaje esperado.fuente
Si una solución no sed es aceptable, este fragmento de PERL hará el trabajo:
fuente
SOLO BESO CORTO SED PURO
haré esto
y funciona
fuente