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
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ä asettaamyvar
(kohdassaconfig.cfg
) arvoon-e
ja näet tyhjän rivin, koskaecho
ajattelee, että se on lippu. Muttaprintf
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 jotainecho "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
*
, mutta sitten mikä Bashissa käsittelee kyseistä merkkiä hyvin?my\\password