Käytä konfigurointitiedostoa komentotiedostossani

Minun on luotava määritystiedosto omalle komentotiedostolleni:
Tässä on esimerkki:

komentosarja:

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

/home/myuser/test/config:

nam="Mark" sur="Brown" 

se toimii!

Kysymykseni: on tämä oikea tapa tee tämä vai onko ”muita tapoja?

Kommentit

  • Muuttujien tulisi olla yläreunassa. I ’ m yllättyi siitä, että se toimii. Miksi tarvitset määritystiedostoa? Aiotko käyttää näitä muuttujia muualla?
  • Faheem, tarvitsen muuttujia, koska komentosarjalla on monia vaihtoehtoja: config-tiedosto puolittaa komentosarjan. Kiitos
  • IMHO sen hienosta. Tein näin.
  • abcde tekee sen myös tällä tavalla ja se on melko iso ohjelma (shell-komentosarjalle). Voit tarkastella sitä täällä .

Vastaus

source ei ole turvallinen, koska se suorittaa mielivaltaisen koodin. Tämä ei välttämättä ole sinulle huolenaihe, mutta jos tiedostojen käyttöoikeudet ovat virheelliset, tiedostojärjestelmää käyttävällä hyökkääjällä voi olla mahdollista suorittaa koodi etuoikeutettuna käyttäjänä injektoimalla koodia muuten suojatun komentosarjan, kuten init-skripti.

Tähän mennessä paras ratkaisu, jonka olen tunnistanut, on kömpelö pyörän keksiminen:

myscript.conf

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

Käyttämällä source, tämä suoritettaisiin echo rm -rf / kahdesti ja muutettaisiin käynnissä olevaa käyttäjää ”s $PROMPT_COMMAND. Tee sen sijaan tämä:

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 -yhteensopiva)

#!/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 

Vastaa, jos löydän koodistani tietoturva-aukon.

Kommentit

  • FYI on Bash-version 4.0 ratkaisu, johon valitettavasti sovelletaan hulluja lisenssiongelmia , jotka Apple on asettanut eikä se ole oletusarvoisesti käytettävissä Mac-tietokoneissa. > @Sukima Hyvä asia. Olen ’ lisännyt version, joka on yhteensopiva Bash 3: n kanssa. Sen heikkous on, että se ei käsittele tuloja *, mutta sitten mikä Bashissa käsittelee kyseistä merkkiä hyvin?
  • Ensimmäinen komentosarja epäonnistuu, jos salasanassa on vinoviiva.
  • @Kusalananda Entä jos taaksepäin on vältetty? my\\password
  • Tämä versio vie muutaman sekunnin määritystiedostoni käsittelyyn. Löysin ratkaisun gw0: sta paljon nopeammaksi.

Vastaa

jäsennä määritystiedosto, älä suorita sitä.

Kirjoitan tällä hetkellä töissä sovellusta, joka käyttää erittäin yksinkertaista XML-määritystä:

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

Shell-komentosarjassa (”sovellus”) teen tämän saadakseni käyttäjätunnuksen (enemmän tai vähemmän, olen laittanut sen shell-toimintoon):

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

Komento xml on XMLStarlet , joka on saatavana useimmille Unices-laitteille.

Käytän XML: ää, koska muut sovelluksen osat käsittelevät myös XML-tiedostoihin koodattuja tietoja, joten se oli helpoin.

Jos haluat JSON: n, siellä on ”s jq , joka on helppokäyttöinen shell-JSON-jäsennin.

Asetustiedostoni näyttäisi tältä tältä JS: ssä PÄÄLLÄ:

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

Ja sitten saisin käyttäjänimen komentosarjaan:

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

Kommentit

  • Komentosarjan suorittamisella on useita etuja ja haittoja. Suurimmat haittapuolet ovat turvallisuus, jos joku voi muuttaa konfigurointitiedostoa, hän voi suorittaa koodin, ja siitä on vaikeampi tehdä idioottivarmaksi. Etuja ovat nopeus, yksinkertaisella testillä konfigurointitiedoston hankkiminen on yli 10000 kertaa nopeampi kuin pq: n suorittaminen, ja joustavuus, kuka tahansa, joka pitää apinoiden korjaustyökalusta, arvostaa tätä.
  • @icarus Kuinka iso kokoonpanotiedostot kohtaat yleensä ja kuinka usein sinun on jäsennettävä ne yhdessä istunnossa? Huomaa myös, että useita arvoja XML: stä tai JSONista voi olla poissa yhdellä kertaa.
  • Yleensä vain muutama (1-3) arvo. Jos asetat eval useiden arvojen asettamiseen, suoritat määritystiedoston valitut osat :-).
  • @icarus Ajattelin taulukoita … Ei tarvitse eval mitään. Suorituskyky, kun käytetään vakiomuotoa olemassa olevalla jäsentimellä (vaikka se ’ on ulkoinen apuohjelma), on merkityksetön verrattuna robustiuteen, koodin määrään, helppokäyttöisyyteen ja ylläpidettävyys.
  • +1 jäsenelle ” jäsennä määritystiedosto, älä ’ t suorita sitä ”

Vastaa

Tässä on puhdas ja kannettava versio, joka on yhteensopiva Bash 3: n ja ylös, sekä Macissa että Linuxissa.

Se määrittelee kaikki oletusarvot erilliseen tiedostoon, jotta vältetään valtavan, sekaannetun, päällekkäisten ”oletusarvojen” määritystoiminnon tarve kaikissa shell-komentosarjoissasi. Ja sen avulla voit valita lukemisen oletusvarauksien kanssa tai ilman:

config.cfg :

myvar=Hello World 

config.cfg.defaults :

myvar=Default Value othervar=Another Variable 

config.shlib (tämä on kirjasto, joten ei ole shebang-riviä):

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 (tai komentosarjat, joihin haluat lue määritysarvot) :

#!/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 

Testiohjelman selitys:

  • Huomaa, että test.sh: n config_get: n kaikki käytöt on kääritty lainausmerkeihin. Käärimällä jokainen config_get lainausmerkeiksi varmistamme, että muuttujan arvon tekstiä ei koskaan tulkita väärin lippuina. Ja se varmistaa, että välilyönnit säilytetään oikein, kuten useita välilyöntejä peräkkäin konfiguraatioarvossa.
  • Ja mitä se printf rivi on? ”S jotain, josta sinun tulisi olla tietoinen: echo on huono komento tekstin tulostamiseen, jota et voi hallita. Vaikka käytät kaksoislainauksia, se tulkitsee liput. Yritä asettaa myvar (kohdassa config.cfg) arvoon -e ja näet tyhjän rivin, koska echo ajattelee, että se on lippu. Mutta printf ei ole tätä ongelmaa. printf -- sanoo ”tulosta tämä, älä tulkitse mitään lippuina”, ja "%s\n" sanoo, että ”muotoile lähtö merkkijonona viimeisellä rivillä, ja viimeinen parametri on printf: n muotoilemisen arvo.
  • Jos et kaiku arvoja näytölle, sinun ei tarvitse yksinkertaisesti määrittää niitä normaalisti, kuten myvar="$(config_get myvar)";. Jos aiot tulostaa ne ruudulle, suosittelen, että printf on täysin turvallinen kaikilta yhteensopimattomilta merkkijonoilta, jotka saattavat olla käyttäjän kokoonpanossa. Mutta kaiku on hieno, jos käyttäjän antama muuttuja ei ”t kaikuisen merkkijonon ensimmäinen merkki, koska se on ainoa tilanne, jossa ”liput” voidaan tulkita, joten jotain echo "foo: $(config_get myvar)"; on turvallista, koska ” foo ”ei” aloita viivalla ja kertoo sen vuoksi kaikulle, että myöskään muu merkkijono ei ole ”t” lippu. 🙂

Kommentit

  • @ user2993656 Kiitos huomaamastasi, että alkuperäisessä koodissani oli vielä yksityinen konfig-tiedostonimi (environment.cfg) oikean sijasta. Mitä tulee ” tekemäsi echo -n ” muokkaus, se riippuu käytetystä kuoresta. Mac / Linux Bashissa ” echo -n ” tarkoittaa ” kaikua ilman uutta riviä ”, jonka tein välttääkseni uusien rivien jäljittämistä. Mutta näyttää siltä, että se toimii täsmälleen samalla tavalla ilman sitä, joten kiitos muokkauksista!
  • Itse asiassa kirjoitin sen läpi ja kirjoitin sen uudelleen käyttämään printf: tä kaiun sijaan, mikä varmistaa, että ’ Ll päästä eroon riskistä, että kaiut tulkitsevat väärin ” -lippuja ” määritysarvoissa.
  • Pidän todella tästä versiosta. Pudotin config.cfg.defaults niiden määrittelemisen sijasta soittaessani $(config_get var_name "default_value"). tritarget.org/static/…
  • Samoin – tämä on hienoa.

Vastaus

Yleisin, tehokas ja oikea tapa on käyttää source tai . lyhennemuotona. Esimerkiksi:

source /home/myuser/test/config 

tai

. /home/myuser/test/config 

Harkittavaa on kuitenkin tietoturvaongelmat, joita ulkoisen ulkoisen kokoonpanotiedoston käyttäminen voi aiheuttaa, koska lisäkoodi voidaan lisätä. Lisätietoja, mukaan lukien ongelman havaitseminen ja ratkaiseminen, suosittelen katsomaan http://wiki.bash-hackers.org/howto/conffile#secure_it

kommentit

  • Toivoin suuresti artikkelia (tuli myös hakutuloksissani), mutta kirjoittaja ’ Ehdotus yrittää käyttää regexiä suodattamaan haitallinen koodi on turhuus.
  • Pistemenetelmä vaatii absoluuttisen polun?Suhteellisena se ei toimi ’ ei toimi

Vastaa

Käytän tätä komentosarjoissani:

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 } 

Pitäisi tukea kaikkia merkkikombinaatioita, paitsi että näppäimillä ei voi olla = niissä, koska se on erotin. Kaikki muu toimii.

% 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 

Tämä on myös täysin turvallista, koska siinä ei käytetä source tai eval.

Kommentit

  • Ei ’ t tätä oletettua Luodaksesi ensin määritystiedoston, jos sitä ei ’ ole? Se ei ole ’ t, mutta touch -a "${path}" varmistaa tietysti sen olemassaolon myös päivittämättä kevyesti sen mtimeä.

Vastaa

Tämä on ytimekäs ja turvallinen:

# 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`) 

-i varmistaa, että muuttujat saat vain osoitteesta common.vars

Päivitys: Suojauksen esimerkki on se, että

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

ei tuota yhtään kosketettua tiedostoa. Testattu Macilla bash: lla, ts. käyttämällä bsd env: tä.

Kommentit

  • Katso vain, kuinka evil1- ja evil2-tiedostot luodaan, jos laitat tämän komentoon on.vars ” `touch touch1 foo = omg boo = $ (touch evil2) ` `
  • @pihentagy Minulle seuraava ei tuota mitään koskemattomia tiedostoja env -i 'touch evil1 foo=omg boo=$(touch evil2)' . Käynnissä Macilla.
  • todellakin, mutta ei voi käyttää foo. Olen ’ kokeillut env -i ... myscript.sh ja komentosarjan sisällä foo ei ole määritelty. Jos kuitenkin poistat ” roskat ”, se toimii. Joten kiitos selittämisestä. : +1:

vastaus

Useimmilla käyttäjillä on jo git binaarinen. Miksi et siis käytä git config sovelluksen kokoonpanon hallintaan käyttämällä erillistä ei-ristiriitaista määritystiedostoa kuten alla olevissa esimerkeissä?

# 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 

Katso lisää komentoja sen manista sivu. On viisasta varmistaa ensin, että määritystiedosto on olemassa:

touch -a ~/.myapp 

Vastaa

Tämä näyttää turvalliselta ja lyhyeltä. Voit murtaa tämän haluttomasti. Haluaisin tietää paremman tavan.

TL; DR;

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

I ”m käyttäen bash 4.3.48.

Se on myös yhteensopiva bash --posix kanssa. Katso testi alareunasta.

Mutta sh ei tue sitä declare vuoksi.


Perustesti niille, jotka haluavat todisteen

Luo tiedosto 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"  

Lataa määritys koodinpätkällä

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

Tulos (katso puhdistusaine toiminnassa)

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 

Tarkistetaan nyt arvot

 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" 

Tarkista sivuvaikutukset (ei sivuvaikutuksia):

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

Liite. Testaa 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 

vastaus

Oma skenaario, source tai . w niin hienosti, mutta halusin tukea paikallisia ympäristömuuttujia (ts. FOO=bar myscript.sh) etusijalla määritettyihin muuttujiin nähden. Halusin myös, että asetustiedosto on käyttäjän muokattavissa ja mukava joku, joka on tottunut hankkimaan määritystiedostoja, ja pitämään sen mahdollisimman pienenä / yksinkertaisena, jotta se ei häiritse hyvin pienen komentojoni päätehtävää. > Tämän keksin:

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) 

Pohjimmiltaan – se tarkistaa muuttujien määritelmät (olematta erittäin joustava välilyönnin suhteen) ja kirjoittaa nämä rivit uudelleen siten, että arvo muunnetaan kyseisen muuttujan oletusarvoksi, ja muuttujaa ei muuteta, jos se löytyy, kuten yllä oleva muuttuja XDG_CONFIG_HOME. Se hankkii tämän muutetun version konfigurointitiedostosta ja jatkaa sitä.

Tulevat työt voivat tehdä komentosarjasta sed vankemman, suodattaa outoilta näyttävät rivit ”. T-määritelmät jne. eivät riko rivin lopussa olevia kommentteja – mutta tämä on minulle riittävä toistaiseksi.

Vastaa

Voit tehdä sen:

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

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *