Es gibt ein bisschen Raum für Verbesserungen. Beginnen wir hier:
v1=($(cat $INPUT | jq '."config"[$i]."var1"[]'))
... erste, die Sie nicht wirklich cat
verwenden müssen; Es verlangsamt Ihre Leistung, weil es jq
zwingt, von einer Pipe lieber als von Ihrer Eingabedatei direkt zu lesen. Nur jq <"$INPUT"
auszuführen wäre robuster (oder, besser, <"$input"
, um die Verwendung von Großbuchstaben zu vermeiden, die durch Konvention für Shell-Built-Ins und Umgebungsvariablen reserviert sind).
Zweitens müssen Sie alle Variablenerweiterungen angeben, einschließlich der Erweiterung des Namens der Eingabedatei - andernfalls erhalten Sie Fehler, wenn Ihr Dateiname Leerzeichen enthält.
Drittens array=($(stuff))
die Ausgabe von stuff
auf alle Zeichen in IFS und erweitert als eine Reihe von glob Ausdrücke teilt (so die Ergebnisse dieser Spaltung, wenn die Ausgabe enthält *.txt
, und Sie laufen dieses Skript in einem Verzeichnis, das Textdateien enthält, erhalten Sie die Namen dieser Dateien in Ihrem Ergebnis-Array). Wenn Sie nur auf Zeilenumbrüche splitten, bedeutet dies, dass Sie Mehrwort-Strings korrekt syntaktisch analysieren können, und das Deaktivieren der Glob-Erweiterung ist erforderlich, bevor Sie diese Technik bei Vorhandensein von Glob-Zeichen zuverlässig verwenden können. Eine Möglichkeit dazu besteht darin, IFS=$'\n'
zu setzen und set -h
auszuführen, bevor dieser Befehl ausgeführt wird. Ein anderer besteht darin, die Ausgabe Ihres Befehls in eine while read
-Schleife umzuleiten (siehe unten).Die String-Ersetzung in Code ist in jeder Sprache eine schlechte Übung - so liegt (Bobby Tables) jemand, der nur in der Lage sein soll, die in Ihren Prozess übergebenen Daten zu ändern, um Inhalte bereitzustellen, die verarbeitet werden als ausführbarer Code (wenn auch in diesem Fall als jq
Skript, das weniger gefährlich ist als die Ausführung willkürlichen Codes in einer volleren Sprache; trotzdem können dadurch zusätzliche Daten zur Ausgabe hinzugefügt werden).
Als nächstes, wenn Sie jq
auszusenden Newline getrennte Inhalte sind immer, brauchen Sie es nicht in einem Array überhaupt zu lesen: Sie können über den Inhalt iterieren, wie es aus jq
und lesen Sie in der Shell geschrieben, und verhindert so die Shell aus, um Speicher zuzuweisen, dass der Inhalt zu puffern:
while IFS= read -r; do
echo "read content from jq: $REPLY"
done < <(jq -r --arg i "$i" '.config[$i | tonumber].var1[]' <"$input")
Endlich - sagen wir, Sie tun wollen mit einem Array arbeiten. Es gibt zwei Möglichkeiten, um Fehler zu vermeiden. Eine davon ist IFS
explizit zu setzen und glob Expansion vor der Zuweisung deaktivieren:
IFS=$'\n' # split only on newlines
set -f
result=($(jq -r ... <"$input"))
Die andere mit einer Schleife zu Ihrem Array zuzuweisen ist:
result=()
while IFS= read -r; do
result+=("$REPLY")
done < <(jq -r ... <"$input")
... oder, wie von @JohnKugelman vorgeschlagen zu verwenden read -a
das gesamte Array in einem Arbeitsgang zu lesen:
IFS=$'\n' read -r -d '' -a result < <(jq -r ... <"$input")
Hier gibt es einige sehr detaillierte Antworten. Meine bevorzugte Lösung, obwohl ihre Relevanz vom Kontrollfluss Ihres Skripts abhängt: 'each_obj() { lokal cmd =" $ 1 "json_arr =" $ 2 "len i; len = $ (jq 'Länge' <(Echo "$ json_arr")); für ((i = 0; i
Shane
@Shane, würde ich vorschlagen, dass ein bisschen zu invertieren:' json_arr = "$ 1"; shift ", und dann können Sie' "$ @" 'verwenden, um einen Befehl auszuführen, der aus allen anderen Argumenten besteht, ohne die Probleme in http://mywiki.wooledge.org/BashFAQ/050 durch Verwendung von' $ cmd' zu riskieren. –