Listen Sie Variablen mit Präfix auf, wobei das Präfix in einer anderen Variablen gespeichert ist

9

Ich versuche, alle Variablen mit einem bestimmten Präfix aufzulisten, aber dieses Präfix wird dynamisch bestimmt. Zum Beispiel:

prefix=apple_
apple_one=a1
apple_two=a2

Wenn ich es einfach mache:

echo ${!apple_@}

Ich kann die Variablennamen erhalten, die mit apple_ beginnen. Ich möchte dies jedoch tun, indem ich irgendwie das Variablenpräfix verwende. Alles, was ich versucht habe, führt zu einer schlechten Substitution. Zum Beispiel kann ich nicht:

echo ${!${prefix}@}
Angelo
quelle
1
Abhängig von Ihrem genauen Problem möchten Sie möglicherweise Arrays verwenden.
Sparhawk
@Sparhawk Ich habe eine Weile nach dem Absenden der Frage das Gleiche gedacht. Versuche ich wirklich, das Rad neu zu erfinden?
Angelo
Ich erwähne es nur, weil ich versucht habe, dasselbe zu tun. Ich habe die Verwendung von Arrays überarbeitet und obwohl ich meine konzeptionellen Aktivitäten ändern musste, ergab dies am Ende mehr "Sinn". Und schien weniger hacky.
Sparhawk
Ich hatte versucht, assoziative Arrays zu vermeiden, weil ich vor einiger Zeit aufgrund von Portabilitätsproblemen verbrannt wurde. (Ich denke, sie haben begonnen, dies in Bash 4 zu unterstützen.)
Angelo
Ich habe dieselbe Anforderung mit der zusätzlichen Bedingung, dass ich die Variablen exportieren kann, sodass Bash-Arrays ausgeschlossen sind.
Philwalk

Antworten:

7

Bash analysiert keine verschachtelten Variablenerweiterungen. Sie können tun, was Sie wollen eval: Erstellen Sie das Shell-Snippet ${!apple_@}und verwenden Sie es dann in einem Befehl, mit dem Sie es ausführen eval.

prefix=apple_
eval 'vars=(${!'"$prefix"'@})'

Stellen Sie sicher, dass prefixnur gültige Bezeichner enthalten sind, da sonst das Snippet zu irgendetwas führen kann.

evalist normalerweise erforderlich, um mit Variablen zu arbeiten, deren Name dynamisch berechnet wird. In diesem speziellen Fall gibt es jedoch eine völlig andere Möglichkeit, dasselbe zu tun: Verwenden Sie das Vervollständigungssystem. Das Vervollständigungssystem von Bash funktioniert sogar über ein Skript. Das integrierte compgenProgramm listet eine Vervollständigung pro Zeile auf, was nicht eindeutig ist, wenn Vervollständigungen Zeilenumbrüche enthalten können. Dies ist hier jedoch nicht der Fall. Sie enthalten nicht einmal Platzhalterzeichen, sodass die Ausgabe mit einer einfachen Erweiterung ohne Anführungszeichen aufgeteilt werden kann. Dies gibt sicher nichts aus, wenn das Präfix Zeichen enthält, die in Bezeichnern nicht gültig sind.

vars=($(compgen -v "$prefix"))
Gilles 'SO - hör auf böse zu sein'
quelle
2

Sie könnten verwenden env | grep '^prefix'.

Zum Beispiel:

$ env | grep '^LESS'
LESSBINFMT=*u.
LESS=-MMqx4ij3
LESSOPEN=| /usr/bin/lesspipe %s
LESSCLOSE=/usr/bin/lesspipe %s %s

Wenn Sie nur die Werte und nicht die Variablennamen möchten, verwenden Sie awk:

$ env | awk -F= '/^LESS/ {print $2}'
*u.
-MMqx4ij3
| /usr/bin/lesspipe %s
/usr/bin/lesspipe %s %s

(oder drucken Sie $ 1 nur für die Variablennamen)


Update 2019-05-17

Ich wurde durch eine Gegenstimme auf diese Antwort zurückgeführt und stellte fest, dass es eine offensichtliche Verbesserung gibt:

typeset -pfunktioniert besser als env, es gibt alle Variablen aus, ob sie exportiert werden oder nicht. Zum Beispiel:

typeset -p | awk '$3 ~ /^apple_/ { print $3 }'

So verwenden Sie eine Variable anstelle einer festen Zeichenfolge:

prefix=apple_
typeset -p | awk '$3 ~ "^"pfx { print $3 }' pfx="$prefix" 

oder exportieren Sie einfach das Präfix $, damit es im ENVIRON-Array von awk verfügbar ist:

export prefix=apple_
typeset -p | awk '$3 ~ "^"ENVIRON["prefix"] { print $3 }'

Hinweis: Mit ein wenig Arbeit kann dies für andere Shells wie ksh oder zsh verwendet werden. Es ist jedoch wichtig zu beachten, dass das Ausgabeformat für typeset -pin anderen Shells unterschiedlich ist, sodass das awk-Skript entsprechend angepasst werden muss Sie.

cas
quelle
1
Nicht, wenn die Variablen nicht exportiert werden. Und dies kann unterbrochen werden, wenn Umgebungsvariablen Zeilenumbrüche enthalten.
Gilles 'SO - hör auf böse zu sein'
wahr. Nichts ist perfekt, und dies ist ungefähr so ​​nah wie möglich an dem, was das OP wollte. setkann auch verwendet werden, wenn es Ihnen nichts ausmacht, Shell-Funktionen mit Ihren Variablen zu mischen.
Cas
set -o posix; set
Nun
@cas Es ist möglich, genau das zu bekommen, was das OP wollte. Es wäre schwierig, wenn Sie eine POSIX-Lösung wünschen, diese ${!prefix}ist jedoch in erster Linie bash-spezifisch (es ist nicht einmal eine ksh-Funktion).
Gilles 'SO - hör auf böse zu sein'
typeset -pfunktioniert besser als env, gibt alle Variablen aus, unabhängig davon, ob sie exportiert wurden oder nicht. zB typeset -p | awk '$3 ~ /^BASH/ {print $3}'und vermeidet die potenziell gefährliche Verwendung von eval. Ich hätte mich an den Satz erinnern sollen, als ich diese Antwort zum ersten Mal gepostet habe. zu einer Variablen anstelle einer festen Zeichenfolge: prefix="BASH"; typeset -p | awk '$3 ~ "^"prefix { print $3}' prefix="$prefix"
cas
0
preset(){
    eval "printf %b $(#"
          set -- "${1##[0-9]*}" _\[:alnum:]
          [ -z   "${1##*[!$2]*}"  ]|| set |
          sed -ne"s/^\($1[$2]*\)=.*/"'"${\1+\1\\n}" \\/p')
"; }; #"

apple_one="a single apple"
apple_two="an apple and an
apple_three='is not actually set at all'
"

preset apple_

apple_one
apple_two
mikeserv
quelle