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
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
- FYI ez egy Bash 4.0 verziójú megoldás, amely sajnos őrült licencelési problémáknak van kitéve az Apple által, és alapértelmezés szerint nem érhető el Mac gépeken
- @Sukima Jó pont.
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?
my\\password
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 amyvar
beállításával (aconfig.cfg
mezőben)-e
-re, és egy üres sort fog látni, mert aecho
úgy gondolja, hogy ez “zászló”. Deprintf
nincs ez a probléma. Azprintf --
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 valamiecho "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 aconfig.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
abcde
ezt is így teszi, és ez egy elég nagy program (egy shell szkripthez). itt megnézheti.