2016-04-01 7 views
1

Diese assoziative Array Gegeben:Recursively Ersatz auf eine Variable

declare -A variables=(
    [prefix]='/usr' 
    [exec_prefix]='@[email protected]' 
    [libdir]='@[email protected]/lib' 
) 

Ich möchte jedes Auftreten des Musters (wobei die Einfang zB @[email protected] mit prefix) @([^@/]+)@ ersetzen mit dem Wert, der der Erfassung zugeordnet ist (zB /usr für prefix) in allen seinen Werten, so dass die Substitution rekursiv durchgeführt wird, bis keine Vorkommen mehr auftreten. Die Schritte für jeden Schlüssel im Array wären:

  1. Rufen Sie den zugehörigen Wert ab und führen Sie (2) darauf aus.
  2. Überprüfen Sie, ob das Muster in der angegebenen Zeichenfolge übereinstimmt.
    • Wenn es keine gibt, geben Sie die angegebene Zeichenfolge zurück.
    • Wenn es ein Spiel:
      1. Perform (1) auf der Erfassung und das Ergebnis halten.
      2. Ersetzen Sie die Übereinstimmung durch das Ergebnis.
      3. Führen Sie (2) für die resultierende Zeichenfolge aus.
  3. Tropfen der vorherige Wert zugeordnet auf den Schlüssel und Mitarbeiter, um es der letzte String zurückgegeben.

Was auch immer der Ansatz, das gewünschte Ergebnis ist:

prefix=/usr 
exec_prefix=/usr 
libdir=/usr/lib 

Zusätzliche Anforderungen:

  • Selbstreferenzen (beispielsweise [email protected]@) findet nicht statt.
  • Verwenden Sie nach Möglichkeit nur Bash-Dateien.

Beispiel in Lua:

local variables={ 
    prefix="/usr", 
    exec_prefix="@[email protected]", 
    includedir="@[email protected]/include", 
    libdir="@[email protected]/lib", 
    random_one_to_show_off_fancy_recursion="@[email protected]@[email protected]@[email protected]" 
} 

function replacer(variable) 
    return compute_value(variables[variable]) 
end 

function compute_value(s) 
    return s:gsub('@([^@/]+)@',replacer) 
end 

local variable, value = next(variables) 
while variable do 
    variables[variable] = compute_value(value) 

    print(string.format('%-39s\t%s', variable, variables[variable])) 

    variable, value = next(variables,variable) 
end 
+0

Sie haben entweder eine Shell-Lösung überbeansprucht oder suchen kostenlose Beratung. ;-). Was haben Sie versucht, Ihr Problem zu lösen? Vielleicht möchten Sie dafür eine 100-Punkte-Prämie anbieten? Viel Glück. – shellter

+0

Muss dies rekursiv durchgeführt werden? Wofür ist das? – Laurel

+0

@shillter Definitiv keine kostenlose Beratung! Ich habe nichts von dem gepostet, was ich versucht habe, weil es wirklich kompliziert war. Für die Aufzeichnung habe ich verschiedene Ansätze ausprobiert, die 'eval' beinhalten und mehrere Probleme betreffen, hauptsächlich die Expansionsreihenfolge (zum Beispiel sollte' libdir' nicht vor 'exec_prefix' bewertet werden). Ich bin mit einem Lua-Skript gelandet, aus dem ich das obige Beispiel extrahiert habe, aber ich möchte Lua nicht zu einer Anforderung für Benutzer machen. – Kalrish

Antwort

2

Die (reine Bash) nachfolgenden Code geht davon aus, dass '@@' bleibt unverändert und '@ xyz @' unverändert gelassen wird, wenn 'xyz' ist keine Variable. Es versucht auch rekursive Variablendefinitionen zu erkennen, einschließlich indirekter (z. B. [a][email protected]@ [b][email protected]@ [c][email protected]@).

# Regular expression for a string with an embedded expansion 
# For a string of the form '[email protected]@w', where 'u' and 'v' do not contain '@': 
# u -> BASH_REMATCH[1] 
# v -> BASH_REMATCH[2] 
# w -> BASH_REMATCH[3] 
readonly EXPANSION_RX='^([^@]*)@([^@]*)@(.*)$' 

# First pass tries to expand all variables 
vars_to_expand=("${!variables[@]}") 

while ((${#vars_to_expand[*]} > 0)) ; do 
    old_vars_to_expand=("${vars_to_expand[@]}") 
    vars_to_expand=() 
    for var in "${old_vars_to_expand[@]}" ; do 
     val=${variables[$var]} 
     unexpanded=$val 
     newval= 

     while [[ $unexpanded =~ $EXPANSION_RX ]] ; do 
      newval+=${BASH_REMATCH[1]} 
      v=${BASH_REMATCH[2]} 
      unexpanded=${BASH_REMATCH[3]} 

      if [[ $v == "$var" ]] ; then 
       echo "ERROR - Expanding '@[email protected]' in '$var'" >&2 
       exit 1 
      elif [[ -z $v ]] ; then 
       # The empty string can not be a hash key (Duh!) 
       [email protected][email protected] 
      else 
       newval+=${variables[$v][email protected][email protected]} 
      fi 
     done 

     newval+=$unexpanded 

     if [[ $newval != "$val" ]] ; then 
      # An expansion has occurred. 

      # Update the variable value 
      variables[$var]=$newval 

      # Further expansions may be possible, so add the variable to the 
      # list of variables to be expanded again 
      vars_to_expand+=("$var") 
     fi 
    done 
done