Konfigurációs fájl használata a shell parancsfájlomhoz

Létre kell hoznom egy konfigurációs fájlt a saját szkriptem számára:
Íme egy példa:

szkript:

#!/bin/bash source /home/myuser/test/config echo "Name=$nam" >&2 echo "Surname=$sur" >&2 

A /home/myuser/test/config tartalma:

nam="Mark" sur="Brown" 

ez működik!

Kérdésem: ez a helyes módszer csináld ezt, vagy “más módon”?

Megjegyzések

  • A változóknak felül kell lenniük. I ‘ m meglepődött, hogy működik. Egyébként miért van szükség konfigurációs fájlra? Tervezed-e, hogy máshol használod ezeket a változókat?
  • Faheem, szükségem van a változókra, mert a szkriptemnek számos lehetősége van: A config fájl félig egyszerűsíti a szkriptet. Köszönet
  • IMHO a rendben. Én így csinálnám.
  • abcde ezt is így teszi, és ez egy elég nagy program (egy shell szkripthez). itt megnézheti.

Válasz

source nem biztonságos, mert tetszőleges kódot fog végrehajtani. Ez nem biztos, hogy aggodalomra ad okot, de ha a fájlengedélyek helytelenek, előfordulhat, hogy a fájlrendszer-hozzáféréssel rendelkező támadó kiváltságos felhasználóként hajthatja végre a kódot úgy, hogy kódot injektál egy konfigurációs fájlba, amelyet egy különben biztosított szkript, például egy init szkript.

Eddig a legjobb megoldás, amit azonosítani tudtam, az az esetlen újrataláló kerék megoldás:

myscript.conf

password=bar echo rm -rf / PROMPT_COMMAND="echo "Sending your last command $(history 1) to my email"" hostname=localhost; echo rm -rf / 

A source használata, ez kétszer futtatná a echo rm -rf / -t, valamint megváltoztatná a futó “s $PROMPT_COMMAND felhasználót. Ehelyett tegye ezt:

myscript.sh (Bash 4)

#!/bin/bash typeset -A config # init array config=( # set default values in config array [username]="root" [password]="" [hostname]="localhost" ) while read line do if echo $line | grep -F = &>/dev/null then varname=$(echo "$line" | cut -d "=" -f 1) config[$varname]=$(echo "$line" | cut -d "=" -f 2-) fi done < myscript.conf echo ${config[username]} # should be loaded from defaults echo ${config[password]} # should be loaded from config file echo ${config[hostname]} # includes the "injected" code, but it"s fine here echo ${config[PROMPT_COMMAND]} # also respects variables that you may not have # been looking for, but they"re sandboxed inside the $config array 

myscript.sh (Mac / Bash 3-kompatibilis)

#!/bin/bash config() { val=$(grep -E "^$1=" myscript.conf 2>/dev/null || echo "$1=__DEFAULT__" | head -n 1 | cut -d "=" -f 2-) if [[ $val == __DEFAULT__ ]] then case $1 in username) echo -n "root" ;; password) echo -n "" ;; hostname) echo -n "localhost" ;; esac else echo -n $val fi } echo $(config username) # should be loaded from defaults echo $(config password) # should be loaded from config file echo $(config hostname) # includes the "injected" code, but it"s fine here echo $(config PROMPT_COMMAND) # also respects variables that you may not have # been looking for, but they"re sandboxed inside the $config array 

Kérjük, válaszoljon, ha biztonsági kódot talál a kódomban.

Megjegyzések

hozzáadtam egy verziót, amely kompatibilis a Bash 3-zal. Gyengesége, hogy nem fogja megfelelően kezelni a*bemeneteket, de aztán mi a Bash-ban, jól kezeli ezt a karaktert?

  • Az első szkript meghiúsul, ha a jelszó visszavonást tartalmaz.
  • @Kusalananda Mi van, ha a visszavágót elkerüljük? my\\password
  • Ez a verzió néhány másodpercet vesz igénybe a konfigurációs fájlom feldolgozása, a gw0-ból származó megoldást sokkal gyorsabbnak találtam.
  • Válasz

    A konfigurációs fájl elemzése, ne hajtsa végre.

    Jelenleg olyan alkalmazást írok a munkahelyén, amely rendkívül egyszerű XML konfigurációt használ:

    <config> <username>username-or-email</username> <password>the-password</password> </config> 

    A shell szkriptben (az “alkalmazás”) ezt csinálom, hogy a felhasználónévhez (több vagy kevesebb, “shell-függvénybe helyeztem):

    username="$( xml sel -t -v "/config/username" "$config_file" )" 

    A xml parancs XMLStarlet , amely a legtöbb Unice számára elérhető.

    XML-t használok, mivel az alkalmazás más részei az XML fájlokban kódolt adatokkal is foglalkoznak, tehát ez volt a legkönnyebb.

    Ha a JSON-ot részesíti előnyben, ott a “s jq , amely egy könnyen használható shell JSON-elemző.

    A konfigurációs fájlom a JS-ben valami ilyesmi lehet BE:

    { "username": "username-or-email", "password": "the-password" } 

    És akkor megkapom a felhasználónevet a szkriptben:

    username="$( jq -r ".username" "$config_file" )" 

    Megjegyzések

    • A parancsfájl végrehajtásának számos előnye és hátránya van. A fő hátrány a biztonság, ha valaki módosíthatja a konfigurációs fájlt, akkor futtathatja a kódot, és nehezebb idiótává tenni. Az előnyök a sebesség, egy egyszerű teszt esetén több mint 10 000-szer gyorsabb egy konfigurációs fájl beszerzése, mint a pq futtatása, és a rugalmasság, aki kedveli a majomfoltosító pitont, értékelni fogja ezt.
    • @icarus Milyen nagy konfigurációs fájlokkal általában találkozik, és milyen gyakran kell elemeznie őket egy munkamenet során? Figyelje meg azt is, hogy az XML-ből vagy a JSON-ból egyszerre több érték is előfordulhat.
    • Általában csak néhány (1-3) érték. Ha a eval fájlt használja több érték beállításához, akkor a konfigurációs fájl kiválasztott részeit hajtja végre :-).
    • @icarus tömbökön gondolkodtam … Nincs szükség eval semmire. A szabványos formátum meglévő elemzővel történő használata (annak ellenére, hogy ‘ külső segédprogram) elenyésző a robusztussághoz, a kód mennyiségéhez, a könnyű használathoz képest , és a karbantarthatóság.
    • +1 a ” elemhez a konfigurációs fájl elemzéséhez, ne ‘ t hajtsa végre ”

    Válasz

    Itt van egy tiszta és hordozható verzió, amely kompatibilis a Bash 3 és fel, mind Mac, mind Linux alatt.

    Az összes alapértelmezett értéket külön fájlban határozza meg, hogy elkerülje az összes shell parancsfájl hatalmas, rendetlen, duplikált “alapértelmezett” konfigurációs funkciójának szükségességét. Ez lehetővé teszi a választást az alapértelmezett tartalékokkal vagy anélkül:

    config.cfg :

    myvar=Hello World 

    config.cfg.defaults :

    myvar=Default Value othervar=Another Variable 

    config.shlib (ez egy könyvtár, tehát nincs shebang-line):

    config_read_file() { (grep -E "^${2}=" -m 1 "${1}" 2>/dev/null || echo "VAR=__UNDEFINED__") | head -n 1 | cut -d "=" -f 2-; } config_get() { val="$(config_read_file config.cfg "${1}")"; if [ "${val}" = "__UNDEFINED__" ]; then val="$(config_read_file config.cfg.defaults "${1}")"; fi printf -- "%s" "${val}"; } 

    test.sh (vagy bármilyen szkript, ahová szeretne konfigurációs értékek beolvasása) :

    #!/usr/bin/env bash source config.shlib; # load the config library functions echo "$(config_get myvar)"; # will be found in user-cfg printf -- "%s\n" "$(config_get myvar)"; # safer way of echoing! myvar="$(config_get myvar)"; # how to just read a value without echoing echo "$(config_get othervar)"; # will fall back to defaults echo "$(config_get bleh)"; # "__UNDEFINED__" since it isn"t set anywhere 

    A teszt parancsfájl magyarázata:

    • Vegye figyelembe, hogy a config.get összes felhasználása a test.sh fájlban dupla idézőjelekbe van foglalva. Azáltal, hogy minden config_get-et dupla idézőjelekbe csomagolunk, biztosítjuk, hogy a változó értékű szöveget soha nem tévesen értelmezzük zászlóként. És biztosítja, hogy megfelelően megőrizzük a szóközöket, például a sorban több szóközt a konfigurációs értékben.
    • És mi az a printf sor? Nos, ez “Olyan dolog, amiről tudnia kell: echo egy rossz parancs olyan szöveg nyomtatásához, amely felett Önnek nincsen irányítása. Még akkor is, ha dupla idézőjeleket használ, értelmezi a zászlókat. Próbálkozzon a myvar beállításával (a config.cfg mezőben) -e -re, és egy üres sort fog látni, mert a echo úgy gondolja, hogy ez “zászló”. De printf nincs ez a probléma. Az printf -- azt mondja: “nyomtassa ki ezt, és ne értelmezzen semmit zászlóként”, és az "%s\n" azt mondja, hogy “formázza a kimenetet stringként záró újsorral, és végül az utolsó paraméter a printf formázandó értéke.
    • Ha nem fog visszhangozni értékeket a képernyőn, akkor egyszerűen rendesen hozzárendeli őket, például myvar="$(config_get myvar)";. Ha kinyomtatja őket a képernyőre, azt javaslom, hogy a printf használatával teljesen biztonságos legyen a visszhangokkal nem kompatibilis karakterláncok ellen, amelyek a felhasználói konfigurációban lehetnek. De az echo rendben van, ha a felhasználó által megadott változó nem “t az általad visszhangzott karakterlánc első karaktere, mivel ez az egyetlen helyzet, ahol a “zászlók” értelmezhetők, így valami echo "foo: $(config_get myvar)"; hasonlóan biztonságos, mivel a ” a foo “nem” kezdődik kötőjellel, ezért elmondja az echo-nak, hogy a többi karakterlánc sem “t” jelöli. 🙂

    Megjegyzések

    • @ user2993656 Köszönjük, hogy észrevette, hogy az eredeti kódomban még mindig a privát konfigurációs fájlnevem (environment.cfg) volt a helyes helyett. Ami a ” Az echo -n ” szerkesztés, amelyet a használt héj függ. Mac / Linux Bash rendszeren ” echo -n ” jelentése: ” visszhang, új sor nélkül. “, amit azért tettem, hogy elkerüljem az új sorok elmaradását. De úgy tűnik, hogy ugyanúgy működik nélküle, ezért köszönöm a szerkesztéseket!
    • Valójában csak átnéztem és átírtam, hogy az echo helyett a printf-et használjam, ami biztosítja, hogy ‘ Meg fog szabadulni a ” zászlók ” hibás értelmezésének visszhangjától a konfigurációs értékekben.
    • Nagyon szeretem ezt a verziót. A (z) $(config_get var_name "default_value") híváskor definiáltam helyett a config.cfg.defaults -t dobtam le. tritarget.org/static/…
    • Hasonlóképpen – ez nagyszerű.

    Válasz

    A leggyakoribb, leghatékonyabb és helyes módszer a source, vagy ., mint gyorsírás. Például:

    source /home/myuser/test/config 

    vagy

    . /home/myuser/test/config 

    Fontos szempont azonban a biztonsági problémák, amelyeket egy további külső forrásból származó konfigurációs fájl használata felvethet, mivel további kódot lehet beilleszteni. További információkért, beleértve a probléma felderítését és megoldását, javasoljuk, hogy nézze át a http://wiki.bash-hackers.org/howto/conffile#secure_it

    Megjegyzések

    • Nagy reményeket fűztem ehhez a cikkhez (a keresési eredményeim között is felmerült), de a szerző ‘ A rosszindulatú kód kiszűrésére irányuló regex használatának megkísérlése a hiábavalóság gyakorlata.
    • A ponttal végzett eljáráshoz abszolút elérési út szükséges?A relatívval ‘ nem működik

    Válasz

    Ezt használom a szkriptjeimben:

    sed_escape() { sed -e "s/[]\/$*.^[]/\\&/g" } cfg_write() { # path, key, value cfg_delete "$1" "$2" echo "$2=$3" >> "$1" } cfg_read() { # path, key -> value test -f "$1" && grep "^$(echo "$2" | sed_escape)=" "$1" | sed "s/^$(echo "$2" | sed_escape)=//" | tail -1 } cfg_delete() { # path, key test -f "$1" && sed -i "/^$(echo $2 | sed_escape).*$/d" "$1" } cfg_haskey() { # path, key test -f "$1" && grep "^$(echo "$2" | sed_escape)=" "$1" > /dev/null } 

    Minden karakterkombinációt támogatnia kell, kivéve, ha a kulcsoknak nem lehet = bennük, mivel ez az elválasztó. Minden más működik.

    % cfg_write test.conf mykey myvalue % cfg_read test.conf mykey myvalue % cfg_delete test.conf mykey % cfg_haskey test.conf mykey || echo "It"s not here anymore" It"s not here anymore 

    Ez is teljesen biztonságos, mivel nem használja a source vagy a eval.

    Megjegyzések

    • Nem ‘ először létre kell hoznia a konfigurációs fájlt, ha nem létezik ‘? Nem ‘ t, hanem touch -a "${path}" természetesen biztosítja, hogy létezik, az mtime komolytalan frissítése nélkül is.

    Válasz

    Ez az tömör és biztonságos:

    # Read common vars from common.vars # the incantation here ensures (by env) that only key=value pairs are present # then declare-ing the result puts those vars in our environment declare $(env -i `cat common.vars`) 

    A -i biztosítja, hogy a

    Frissítés: A biztonság szemléltetése, hogy

    env -i "touch evil1 foo=omg boo=$(touch evil2)" 

    Nem hoz létre megérintett fájlokat. Mac-en tesztelve bash-val, azaz a bsd env használatával.

    Megjegyzések

    • Csak nézze meg, hogyan jönnek létre a evil1 és a evil2 fájlok, ha ezt a on.vars “touch evil1 foo = omg boo = $ (touch evil2)” “
    • @pihentagy Számomra az alábbiak nem hoznak létre megható fájlokat env -i 'touch evil1 foo=omg boo=$(touch evil2)' . Mac rendszeren fut.
    • valóban, de nem érhető el a foo. Megpróbáltam ‘ a env -i ... myscript.sh alkalmazást, és a szkript belsejében a foo nincs meghatározva. Ha azonban eltávolítja a ” szemetet “, akkor ez működni fog. Tehát köszönöm, hogy elmagyarázta. : +1:

    Válasz

    A legtöbb felhasználó, bár nem sok tároló, már rendelkezik a git bináris. Miért ne használná ezért a git config az alkalmazás konfigurációjának kezeléséhez dedikált, nem ütköző konfigurációs fájl segítségével, az alábbi példák szerint?

    # Set $ git config -f ~/.myapp core.mykey myval # Get $ git config -f ~/.myapp core.mykey myval # Get invalid $ git config -f ~/.myapp core.mykey $ echo $? 1 # List git config -f ~/.myapp -l core.mykey=myval # View $ cat ~/.myapp [core] mykey = myval 

    További parancsokért lásd a man oldal. Bölcs dolog először megbizonyosodni arról, hogy létezik a konfigurációs fájl:

    touch -a ~/.myapp 

    Válasz

    Ez biztonságosnak és rövidnek tűnik. Ezt nyugodtan törje meg könyörtelenül. Szeretnék tudni egy jobb módszert.

    TL; DR;

    while read LINE; do declare "$LINE"; done < evil.conf 

    I “m a bash 4.3.48 használatával.

    Ez a bash --posix szabványnak is megfelel. A tesztet lásd az alján.

    De sh nem támogatja a declare miatt.


    Alapvető teszt azok számára, akik igazolást akarnak

    Hozzon létre fájlt a evil.conf

     echo > evil.conf " A=1 B=2 C=$(echo hello) # Could produce side-effect D=`touch evil` C=$((1+2)) E=$(ping 8.8.8.8 -n 3) echo hello # Could produce visible side-effect touch evil2 ping 8.8.8.8 -n 3 F=ok"  

    Töltse be a konfigurációt a kódrészlettel

     while read LINE; do declare "$LINE"; done < evil.conf  

    Kimenet (lásd a fertőtlenítőt működés közben)

    bash: declare: `": not a valid identifier bash: declare: `": not a valid identifier bash: declare: `# Could produce side-effect": not a valid identifier bash: declare: `echo hello": not a valid identifier bash: declare: `": not a valid identifier bash: declare: `# Could produce visible side-effect": not a valid identifier bash: declare: `touch evil2": not a valid identifier bash: declare: `ping 8.8.8.8 -n 3": not a valid identifier 

    Ellenőrizzük az értékeket most

     for V in A B C D E F; do declare -p $V; done  
    declare -- A="1" declare -- B="2" declare -- C="\$((1+2))" declare -- D="\`touch evil\`" declare -- E="\$(ping 8.8.8.8 -n 3)" declare -- F="ok" 

    Ellenőrizze a mellékhatásokat (nincsenek mellékhatások):

     ls evil evil2  
    ls: cannot access "evil": No such file or directory ls: cannot access "evil2": No such file or directory 

    Függelék. Teszt bash --posix

    bash -c "while read LINE; do declare "$LINE"; done < evil.conf; for V in A B C D E F; do declare -p $V; done" --posix 

    Válasz

    A forgatókönyvemhez source vagy . w rendben van, de támogatni akartam a helyi környezeti változókat (azaz FOO=bar myscript.sh), elsőbbséget élvezve a konfigurált változókkal szemben. Azt is szerettem volna, ha a konfigurációs fájl felhasználó által szerkeszthető és kényelmes a konfigurációs fájlokból származó felhasználók számára, és hogy a lehető legkisebb / egyszerűbb legyen, hogy ne vonja el a figyelmet a nagyon kicsi szkriptem fő irányvonaláról.

    Ezt találtam ki:

    CONF=${XDG_CONFIG_HOME:-~/config}/myscript.sh if [ ! -f $CONF ]; then cat > $CONF << CONF VAR1="default value" CONF fi . <(sed "s/^\([^=]\+\) *= *\(.*\)$/\1=${\1:-\2}/" < $CONF) 

    Lényegében – ellenőrzi a változó definíciókat (anélkül, hogy nagyon rugalmas lenne a szóközzel), és átírja ezeket a sorokat, hogy az érték alapértelmezetté konvertálódik az adott változóra, és a változó nem módosul, ha megtalálható, mint a fenti XDG_CONFIG_HOME változó. Forrja a konfigurációs fájl ezen módosított változatát, és folytatja.

    A jövőbeni munkával a sed szkript robusztusabbá válhat, kiszűrheti a furcsának tűnő vagy arénás ” A definíciók stb. nem szakadnak meg a sor végén, de ez nekem egyelőre elég jó.

    Válasz

    Megteheti:

    #!/bin/bash name="mohsen" age=35 cat > /home/myuser/test/config << EOF Name=$name Age=$age EOF 

    Vélemény, hozzászólás?

    Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük