El código de retorno de sed no coincide

Estoy usando sed para actualizar mi archivo de configuración json en el tiempo de ejecución. A veces, cuando el patrón no coincide en el archivo json, todavía sed sale con el código de retorno 0.

Devolver 0 significa completar con éxito, pero ¿por qué sed devuelve 0 si no encuentra el patrón adecuado y actualiza el archivo? ¿Hay alguna solución para eso?

¡Gracias!

como comentó @cnicutar, el código de retorno de un comando significa que el comando se ejecutó con éxito. no tiene nada que ver con la lógica que implementó en los códigos / scripts.

entonces si tienes:

 echo "foo"|sed '/bar/ s/a/b/' 

sed devolverá 0 pero si escribe algunos errores de syntax / expresión, o la entrada / archivo no existe, sed no puede ejecutar su solicitud, sed devolverá 1.

solución alternativa

esto en realidad no es una solución . sed tiene el comando q : (desde la página man):

  q [exit-code] 

aquí puede definir el código de salida como lo desee. Por ejemplo '/foo/!{q100}; {s/f/b/}' '/foo/!{q100}; {s/f/b/}' saldrá con el código 100 si foo no está presente, y de lo contrario realizará la sustitución f-> b y saldrá con el código 0.

Caja emparejada:

 kent$ echo "foo" | sed '/foo/!{q100}; {s/f/b/}' boo kent$ echo $? 0 

Caso sin igual:

 kent$ echo "trash" | sed '/foo/!{q100}; {s/f/b/}' trash kent$ echo $? 100 

Espero que esto responda tu pregunta.

editar

Debo agregar que, el ejemplo anterior es solo para el procesamiento de una línea. No sé tu requerimiento exacto. cuando quieras obtener la exit 1 . una línea sin igual o el archivo completo. Si todo el archivo no coincide con el caso, puede considerar awk, o incluso hacer un grep antes de su procesamiento de texto …

Esto podría funcionar para usted (GNU sed):

 sed '/search-string/{s//replacement-string/;h};${x;/./{x;q0};x;q1}' file 

Si se encuentra la search-string , se reemplazará con replacement-string y al final del archivo sed saldrá con 0 código de retorno. Si no se realiza ninguna sustitución, el código de retorno será 1 .

Una explicación más detallada:

En sed, el usuario tiene dos registros a su disposición: el espacio de patrón (PS) en el que se carga la línea actual (menos el salto de línea) y un registro de reserva llamado espacio de espera (HS) que está inicialmente vacío.

La idea general es usar el HS como una bandera para indicar si se ha producido una sustitución. Si el HS todavía está vacío al final del archivo, no se han realizado cambios, de lo contrario se han producido cambios.

El comando /search-string/ coincide con search-string con lo que está en el PS y si se encuentra que contiene el search-string se ejecutan los comandos entre los siguientes llaves.

En primer lugar, la sustitución s//replacement-string/ (sed utiliza la última expresión regular, es decir, la search-string , si la parte izquierda está vacía, por lo que s//replacement-string es igual a s/search-string/replacement-string/ ) y luego de esto, el comando h hace una copia del PS y lo coloca en el HS.

El comando $ sed se usa para reconocer la última línea de un archivo y luego ocurre lo siguiente.

Primero, el comando x intercambia los dos registros, por lo que el HS se convierte en el PS y el PS en el HS.

Luego se busca el PS por cualquier carácter /./ ( . Significa que coincide con cualquier carácter) recuerde que el HS (ahora el PS) estaba inicialmente vacío hasta que se produjo una sustitución. Si la condición es verdadera, la x se ejecuta nuevamente, seguida del comando q0 que finaliza todo el procesamiento sed y establece el código de retorno en 0 . De lo contrario, se ejecuta el comando x y el código de retorno se establece en 1 .

NB, aunque q deja de procesar sed, no impide que el PS se reensamble por sed y se imprima como de costumbre.

Otra alternativa:

 sed '/search-string/!ba;s//replacement-string/;h;:a;$!b;p;x;/./Q;Q1' file 

o:

 sed '/search-string/,${s//replacement-string/;b};$q1' file 

Estas respuestas son muy complicadas. ¿Qué hay de malo en escribir un poco de script de shell que use grep para averiguar si lo que desea reemplazar está allí y luego usar sed para reemplazarlo?

 grep -q $TARGET_STRING $file if [ $? -eq 0 ] then echo "$file contains the old site" sed -e "s|${TARGET_STRING}|${NEW_STRING}|g" .... fi 

A continuación se muestra el patrón que usamos con sed -rn o sed -r .

El comando completo de búsqueda y reemplazo (“s / … / … / …”) es opcional. Si se utiliza la búsqueda y el reemplazo, para obtener mayor velocidad y haber coincidido con $ matchRe, usamos el valor más rápido posible de $ searchRe, utilizando. donde el personaje no necesita ser re-verificado y. {$ len} para secciones de longitud fija del patrón.

El valor de retorno para ninguno encontrado es $ notFoundExit.

 /$matchRe/{s/$searchRe/$replacement/$options; Q}; q$notFoundExit 

Por las siguientes razones:

  • No se desperdicia tiempo probando para casos coincidentes y sin igual
  • No hay pérdida de tiempo en copiar hacia o desde los almacenamientos intermedios
  • Sin twigs superfluas
  • Flexibilidad razonable

La variación del caso de los comandos Q variará el comportamiento dependiendo de cuándo se producirá la salida. Los comportamientos que implican la aplicación de la lógica booleana a una entrada de línea múltiple requieren más complejidad en la solución.

Quise truncar un archivo al salir cuando se encontró la coincidencia (y excluir la línea correspondiente). Esto es útil cuando un proceso que agrega líneas al final del archivo puede volver a ejecutarse. “Q; Q1” no funcionó, pero simplemente “Q1” lo hizo, de la siguiente manera:

si sed -i ‘/ text Yo quería encontrar / Q1’ file.txt luego inserte una línea en blanco al final del archivo + nuevas líneas fi inserte solo las líneas nuevas sin la línea en blanco

Como ya sabemos, cuando sed no puede coincidir, simplemente devuelve su cadena de entrada, no se ha producido ningún error. Es cierto que una diferencia entre las cadenas de entrada y de salida implica una coincidencia, pero una coincidencia no implica una diferencia en las cadenas; después de todo sed podría simplemente haber coincidido con todos los caracteres de entrada. La falla se crea en el siguiente ejemplo

 h=$(echo "$g" | sed 's/.*\(abc[[:digit:]]\).*/\1/g') if [ ! "$h" = "$g" ]; then echo "1" else echo "2" fi 

donde g=Xabc1 da 1, mientras que el ajuste g=abc1 da 2; sin embargo, ambas cadenas de entrada se corresponden con sed. Por lo tanto, puede ser difícil determinar si sed se corresponde o no. Una solución:

 h=$(echo "fix${g}ed" | sed 's/.*\(abc[[:digit:]]\).*/\1/g') if [ ! "$h" = "fix${g}ed" ]; then echo "1" else echo "2" fi 

en cuyo caso, el 1 se imprime if-and-only-si sed ha coincidido.