Maak een associatieve array uit de uitvoer van twee opdrachten

Ik probeer gebruikersmappen te maken op basis van een geïmporteerd passwd-bestand en probeer de gegevens in een associatieve array: array [gebruikersnaam] = directory. Ik kan de velden in afzonderlijke arrays laden, maar ik kan de associaties niet correct krijgen, omdat elk veld wordt geassocieerd met alle mappen.

USERLIST=$(cat /usrmkr/in.out | awk -F ":" "{print $1}") DIRLIST=$(cat /usrmkr/in.out | awk -F ":" "{print $6}") declare -A USERARRAY func_StoreData() { USERARRAY[$1]="$2" return $? } for ((u=0;u<${USERLIST[@]};u++)); do func_StoreData ${USERLIST[$u]} ${DIRLIST[$u]} done for i in ${!USERARRAY[@]}; do echo "making directory for $i in ${USERARRAY[$i]}" #Do stuff done 

Reacties

  • Als een van de bestaande antwoorden uw probleem oplost, overweeg dan om deze te accepteren via het vinkje. Bedankt!

Antwoord

Je zou het hele ding rechtstreeks met bash kunnen lezen, door te zeggen dat je moet splitsen op dubbele punten :

declare -A userarray while IFS=: read -r username password uid gid gecos home shell; do userarray[$username]=$home done < /usrmkr/in.out 

Antwoord

 eval declare -A USERARRAY=( $(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out) )  

Het awk script produceert uitvoer in het [key]=val formaat vereist bij het instellen van meerdere elementen van een bash associatieve array, en dubbele aanhalingstekens zowel de sleutel als de waarde (["key"]="value") voor het geval er spaties, tabs enz. in de sleutels of de waarden zijn .

Ik “heb \n als scheidingsteken gebruikt om het gemakkelijk te maken voor het geval je de awk output met een andere tool (hoewel awk de meeste dingen kan doen die je misschien met andere tools zou willen doen).

Commando-vervanging zou alleen voldoende moeten zijn .. .maar vanwege wat IMO is, een bug in bash, als het eerste niet-witruimte-teken binnen de ( ... ) matrixdefinitie isn ” ta [, het produceert alleen de foutmelding must use subscript when assigning associative array.

bijv. beide volgende pogingen om USERARRAY in te stellen zullen mislukken:

 $ bash --version | head -1 GNU bash, version 4.3.46(1)-release (x86_64-pc-linux-gnu) $ declare -A USERARRAY=($(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out)) bash: USERARRAY: $(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out): must use subscript when assigning associative array $ UA=$(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out) $ declare -A USERARRAY=( $UA ) bash: USERARRAY: $UA: must use subscript when assigning associative array  

De oplossing is om eval te gebruiken bij het declareren van de gehashte array, zoals in het codevoorbeeld bovenaan mijn antwoord. Of,

eval declare -A USERARRY=( $UA ) 

Reacties

  • 1. dit gebruikt eval – natuurlijk is er ' een risico op commando-injectie. Ik denk echter niet ' niet dat het ' een probleem is in dit geval, omdat mijn antwoord bedoeld is voor gebruik met het OP ' s specifiek & vermoedelijk doorgelicht / bekend goed invoerbestand. 2. " vergat de uitbreidingen te citeren " – hè? wat? Ik zie geen ' probleem met citeren – de awk-code citeert expliciet zowel sleutels als waarden voor de array. 3. Trouwens, bijna 2 jaar later laat bash v4.4.19 (1) -release nog steeds je ' niet direct een cmd-subst of zelfs een var in een hash-declaratie: declare -A array=( $(...) ) mislukt met dezelfde fout, dus eval is nog steeds vereist
  • @St é phaneChazelas Als er ' een citaatprobleem is, leg dan uit hoe en waarom – bij voorkeur met een real-world voorbeeld met geldige / etc / passwd stijlinvoer, zoals relevant is voor deze vraag en het antwoord, niet alleen een algemene en voor de hand liggende " als u afvalgegevens invoert, ' krijgt u onvoorspelbare en potentieel gevaarlijke resultaten ".
  • U ' hebt een punt dat het normaal gesproken geen probleem zou zijn voor typische /etc/passwd gegevens. Dus laat me het anders formuleren: ⚠ hoewel het in orde zou moeten zijn voor typische /etc/passwd gegevens, zou die benadering niet gebruikt moeten worden voor willekeurige gegevens, aangezien dit een kwetsbaarheid voor commando-injectie zou vormen. Concreet gaat het ervan uit dat de gegevens niet ' t bevatten, `, ", backslash, $, *, ?, [, spatie-tab of NUL-tekens.
  • Over het probleem van citeren, zie bijvoorbeeld Veiligheidsimplicaties van het vergeten een variabele te citeren in bash / POSIX-shells en de daar gekoppelde vragen om te zien wat het betekent om uitbreidingen niet te vermelden.
  • Merk op dat oudere versies van bash een bug hadden waarbij ' a = (" $ x ") `zou er niet in slagen om een array te maken waarvan één element de inhoud is van $x toen $x zoiets als [123]=qwe was (dat was vóór door bash ondersteunde associatieve arrays).De ware bash van ' had ervoor kunnen kiezen om associatieve arrays te declareren als a=("$x") (waarbij $x moet beginnen met [...]=) naast de a=([$k]=$v) syntaxis, maar dan zou het een manier hebben moeten definiëren om te specificeren toetsen die] tekens bevatten. In elk geval zou ik het geen bug noemen maar een ontwerpbeslissing (hier gemaakt door ksh waar bash zijn syntaxis van heeft gekopieerd).

Answer

In plaats van twee lijsten samen te voegen, kunnen we de array samenstellen in een enkele lus (en een enkele aanroep naar awk voor een goede meting) door een lijst te retourneren van user: dir-vermeldingen en die vervolgens opsplitsen met variabele uitbreidingen:

#!/bin/bash declare -A USERARRAY for u in $(awk -F: "{print $1 ":" $6}" /usrmkr/in.out) do user=${u%:*} dir=${u#*:} USERARRAY[$user]=$dir done 

Answer

zsh heeft een meer bruikbare, meer gebruikelijke (vergelijkbaar met tcl of perl) manier om associatieve arrays als geheel te declareren: array=(key1 value1 key2 value2...)

typeset -A userarray IFS=$":\n\n" userarray=($(cut -d : -f 1,6 < /usrmkr/in.out)) 

Verdubbeling \n, zoals in ksh93, verwijdert de speciale status van de nieuwe regel als een IFS-witruimteteken . Zonder dit foo:\nbar:x zou worden opgesplitst in “foo”, “bar”, “x” in plaats van “foo”, “”, “bar”, “x”.

Met , de syntaxis is dezelfde lastige als in ksh93: array=([key1]=value1 [key2]=value2), dus je kunt de uitvoer niet gemakkelijk krijgen van een commando in een associatieve array anders dan door een lus te gebruiken waarbij één element tegelijk wordt toegewezen, zoals anderen hebben laten zien.

Merk op dat bash associatieve arrays ( in tegenstelling tot ksh93 of zsh) hebben de beperking dat de sleutel niet de lege tekenreeks kan zijn (geen probleem hier). Een andere beperking, deze keer gedeeld met ksh93, is dat sleutel noch waarden de NUL-byte kunnen bevatten (ook hier geen probleem).

(ondersteuning voor associatieve arrays was in ksh93 vanaf het begin (1993), toegevoegd aan zsh in 1998 (3.1.5-pws-3) en bash in 2009 ( 4.0))

Reacties

  • Waarom heb je ' \ n ' tweemaal in de IFS?
  • @rubystallion zie bewerken

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *