Función Bash con bucle for y declaración if anidada que da un resultado peculiar

Función Bash con bucle for y declaración if anidada que da un resultado peculiar

Tengo la siguiente función bash que me tiene despilfarrado. Si ingreso lo siguiente en las casillas de zenity...

ID de empleado = 2 ID de categoría = 3

Me sale lo siguiente: 2 3

si...

ID de empleado = ID de categoría = 3

Después de que se abre una segunda ventana de zenity, ingreso 2 y obtengo lo siguiente: 2 3

Sin embargo cuando entro

ID de empleado = 2 ID de categoría =

No se abre ninguna ventana adicional de Zenity y aparece lo siguiente: 2

Lo que realmente quiero obtener es 2,3 después de que se hayan realizado las pruebas.

¿Alguien sabe qué está mal aquí?

#!/bin/bash


num(){
        emp=$(echo "$1" | awk -F, -v  OFS=, '{print $1 "," $2}')

        IFS=, read -ra array1 <<<"$emp"
        
        p=$(for i in "${array1[@]}"
        
        do
                
                if [[ "${i}" =~ ^[0-9]+$ ]]; then

                        out="${i}"
                elif
                        [[ "${i}" = NULL ]]; then

                        out="${i}"


                else   local var2

                        until [[ ${var2} =~ ^[0-9]+$ ]] || [[ ${var2} = NULL ]]; do

                                var2="$(zenity --forms --title="table salaries_wages" --text "Add a number"  --separator="," \
                                --add-entry="WARNING! You either forgot to enter or didn't enter a number. Please enter a valid number: ")"

                         done

                                out="${var2}"

        fi

        echo "$out"
        
done)
      
        echo "$p"
}

input="$(zenity --forms --title="table salaries_wages" --text="Add a new salaries_wages entry" --separator="," \
        --add-entry="ENTER employeeid: " \
        --add-entry="ENTER categoryid: ")"

num "$input"

Respuesta1

¿Que esta mal aquí?

Su suposición de cómo readfunciona es diferente de cómo readfunciona realmente. Ejecute este código en Bash:

how_many () { IFS=, read -ra array1 <<<"$1"; echo "${#array1[@]}"; }
how_many "2,3"
how_many ",3"
how_many "2,"

Conseguirás 2, 2, 1. Destaca el último número. Significa que el separador final ( ,en este caso) se trata readmás como un terminador: el campo vacío después de él no se lee en la matriz y la matriz termina siendo un elemento demasiado corto. Si esto sucede en su código, for i in "${array1[@]}"se ejecutará el bucle solo para el primer campo.

La solución puede ser introducir unextra ,como terminador final a propósito. Entonces readnunca leerá el tercer campo, pero siempre leerá dos campos (incluso si el segundo está vacío). Vea la diferencia cuando agrego un extra ,:

how_many () { IFS=, read -ra array1 <<<"$1,"; echo "${#array1[@]}"; }
how_many "2,3"
how_many ",3"
how_many "2,"
how_many ","

La salida es 2cada vez.

Para arreglar su código de esta manera use <<<"$emp,"en lugar de <<<"$emp".


Si corrige el código, se comportará mal cuando el elsebloque se ejecute más de una vez (es decir, cuando ambos campos no sean válidos inicialmente); porque eresreutilizando la var2variablede nuevo.

Supongo que solías local var2evitar esto, pero localhaces que la variable sea local en una función, no en un elsebloque o en una única iteración de un forbucle. Estás reutilizando var2en la misma instancia de la numfunción.

Estás llamando a la función una vez. En su interior var2es siempre el mismo var2, localsólo lo distingue de cualquier var2exterior esta misma invocación de la función. Si lo usara var2fuera de la función, el de la función sería distinto. Si invocaste nummás de una vez, cada invocación usaría su propio archivo var2. Ninguna de estas cosas sucede. Estás llamando a la función una vez y reutilizando la variable.allá. Cuando dos campos no son válidos, la variable se utiliza para el primer campo y luegoreutilizadopara el segundo campo.

Pero si reconstruye su código de modo que validatese llame a alguna función (por ejemplo, ) desde dentro del bucle:

for i in "${array1[@]}"; do validate "$i"; …

y uso local var2en la validatefunción, entonces var2en cada invocación de la función será distinta. Así es como localpuedo ayudar. En cada bucle validatese llamará de nuevo, sus variables locales se inicializarán de nuevo sin ninguna conexión con otras variables con el mismo nombre. Sin embargo, aún podrá reutilizar una variable local.adentrola función de una manera que rompa algo (de manera similar a cómo estás reutilizando actualmente var2en la numfunción).

Después de escribir lo anterior, agregué un ejemplo alrespuesta ya vinculada.


Note p=$(stuff); echo "$p"es casi equivalente a echo "$(stuff)", que casi siempre debería ser justo stuff. Por favor leeesta respuestadonde profundiza var=$(stuff); echo "$var".

información relacionada