Bash-Funktion mit For-Schleife und verschachtelter If-Anweisung liefert eigenartiges Ergebnis

Bash-Funktion mit For-Schleife und verschachtelter If-Anweisung liefert eigenartiges Ergebnis

Ich habe die folgende Bash-Funktion, die mich in Verlegenheit bringt. Wenn ich Folgendes in die Zenity-Felder eingebe ...

Mitarbeiter-ID = 2 Kategorie-ID = 3

Ich erhalte folgendes: 2 3

Wenn...

Mitarbeiter-ID = Kategorie-ID = 3

Nachdem sich ein zweites Zenity-Fenster öffnet, gebe ich 2 ein und erhalte Folgendes: 2 3

Wenn ich jedoch

Mitarbeiter-ID = 2 Kategorie-ID =

Es öffnet sich kein weiteres Zenity-Fenster und ich erhalte folgende Meldung: 2

Am Ende möchte ich nach Abschluss der Tests ein Ergebnis von 2,3 erzielen.

Weiß jemand, was hier nicht stimmt?

#!/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"

Antwort1

was ist hier falsch?

Ihre Annahme, wie reades funktioniert, weicht von der readtatsächlichen Funktionsweise ab. Führen Sie diesen Code in Bash aus:

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

Sie erhalten 2, 2, 1. Die letzte Zahl fällt auf. Das bedeutet, dass das nachfolgende Trennzeichen ( ,in diesem Fall) readeher wie ein Abschlusszeichen behandelt wird: Das leere Feld danach wird nicht in das Array eingelesen und das Array ist am Ende ein Element zu kurz. Wenn dies in Ihrem Code passiert, for i in "${array1[@]}"wird die Schleife nur für das erste Feld ausgeführt.

Die Lösung könnte darin bestehen, eineextra ,als Abschlusszeichen mit Absicht. Dann readwird nie das dritte Feld gelesen, aber immer zwei Felder (selbst wenn das zweite leer ist). Sehen Sie den Unterschied, wenn ich ein zusätzliches hinzufüge ,:

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

Die Ausgabe erfolgt 2jedes Mal.

Um Ihren Code auf diese Weise zu korrigieren, verwenden Sie <<<"$emp,"anstelle von <<<"$emp".


Wenn Sie den Code reparieren, wird er sich falsch verhalten, wenn der elseBlock mehr als einmal ausgeführt wird (d. h. wenn beide Felder anfänglich ungültig sind); denn SieWiederverwendung der var2Variablewieder.

Ich vermute, Sie haben local var2dies früher vermieden, aber localdie Variable lokal in einer Funktion erstellt, nicht in einem elseBlock oder in einer einzelnen Iteration einer forSchleife. Sie verwenden sie var2in derselben Instanz der numFunktion erneut.

Sie rufen die Funktion einmal auf. Darin var2ist immer dasselbe var2, localnur unterscheidet sich var2dieses Aufrufen der Funktion von allen außerhalb. Wenn Sie var2außerhalb der Funktion verwenden würden, wäre das in der Funktion different . Wenn Sie nummehr als einmal aufrufen würden, würde jeder Aufruf sein eigenes distinct verwenden var2. Keines von beidem passiert. Sie rufen die Funktion einmal auf und verwenden die Variable erneutDort. Wenn zwei Felder ungültig sind, wird die Variable für das erste Feld verwendet und dannwiederverwendetfür das zweite Feld.

Wenn Sie Ihren Code jedoch so umbauen, dass eine Funktion (z. B. validate) innerhalb der Schleife aufgerufen wird:

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

local var2und in der validateFunktion verwenden , dann var2wird jeder Aufruf der Funktion unterschiedlich sein. So localkann es helfen. In jeder Schleife validatewird sie neu aufgerufen, ihre lokalen Variablen werden neu initialisiert, ohne Verbindung zu anderen Variablen mit demselben Namen. Sie können jedoch weiterhin eine lokale Variable wiederverwendeninnendie Funktion auf eine Weise, die etwas kaputt macht (ähnlich der Art und Weise, wie Sie es derzeit var2in der numFunktion wiederverwenden).

Nachdem ich das Obige geschrieben hatte, fügte ich ein Beispiel hinzubereits verlinkte Antwort.


Hinweis p=$(stuff); echo "$p"ist fast gleichbedeutend mit echo "$(stuff)", was fast immer nur sein sollte stuff. Bitte lesen Siediese Antwortwo näher darauf eingegangen wird var=$(stuff); echo "$var".

verwandte Informationen