วิธีที่ดีที่สุดในการอ่านไฟล์กำหนดค่าใน bash


23

วิธีที่ดีที่สุดในการอ่านไฟล์กำหนดค่าใน bash คืออะไร?
ตัวอย่างเช่นคุณมีสคริปต์และไม่เต็มใจที่จะเติมการกำหนดค่าทั้งหมดด้วยตนเองทุกครั้งที่คุณเรียกสคริปต์

แก้ไข 1: ฉันคิดว่าฉันไม่ได้ทำให้ชัดเจนดังนั้น: สิ่งที่ฉันต้องการคือ ... ฉันมี configfile ซึ่งเป็นเหมือน

variable_name value  
variable_name value ...  

และฉันต้องการอ่าน ฉันรู้ว่าฉันสามารถ grep มันสำหรับข้อโต้แย้งที่ฉันกำลังมองหาหรือดังนั้น ... แต่อาจจะมีวิธีที่ชาญฉลาดมากขึ้น :)


2
คุณจะต้องแสดงว่าคุณหมายถึงการกำหนดค่าประเภทใด ให้ตัวอย่าง
muru

ดูคำถามที่คล้ายกันมากใน Unix & Linux StackExchange
Michael

คำตอบ:


38

อย่างที่ mbiber พูดsourceไฟล์อื่น ตัวอย่างเช่นไฟล์กำหนดค่าของคุณ (พูดsome.config) จะเป็น:

var1=val1
var2=val2

และสคริปต์ของคุณอาจมีลักษณะ:

#! /bin/bash

# Optionally, set default values
# var1="default value for var1"
# var1="default value for var2"

. /path/to/some.config

echo "$var1" "$var2"

ไฟล์จำนวนมาก/etc/defaultมักใช้เป็นไฟล์กำหนดค่าสำหรับเชลล์สคริปต์อื่น ๆ ในลักษณะเดียวกัน /etc/default/grubตัวอย่างที่พบบ่อยมากจากโพสต์ที่นี่คือ ไฟล์นี้ใช้เพื่อตั้งค่าตัวเลือกการกำหนดค่าสำหรับ GRUB เนื่องจากgrub-mkconfigเป็นเชลล์สคริปต์ที่มา:

sysconfdir="/etc"
#…
if test -f ${sysconfdir}/default/grub ; then
  . ${sysconfdir}/default/grub
fi

หากคุณต้องดำเนินการกำหนดค่าของแบบฟอร์มจริงๆ:

var1 some value 1
var2 some value 2

จากนั้นคุณสามารถทำสิ่งที่ชอบ:

while read var value
do
    export "$var"="$value"
done < /path/to/some.config

(คุณสามารถทำสิ่งที่ชอบeval "$var=$value"ได้ แต่มันมีความเสี่ยงมากกว่าการหาสคริปต์คุณสามารถทำลายไฟล์นั้นได้ง่ายกว่าไฟล์ที่มา)


นั่นเป็นวิธีที่ยอดเยี่ยมฉันสามารถใช้ช่องว่างแทนที่ sed สำหรับ "="
IcyIcyIce

1
@IcyIcyIce ทำไม่ได้ ทำไมคุณถึงเขียนไม่ได้=ตั้งแต่ต้น?
muru

1
@IcyIcyIce นั่นคือสิ่งที่มันควรจะเป็น คุณสามารถใช้รหัสเชลล์ในไฟล์ต่าง ๆ ใน/etc/default- และส่วนใหญ่จะใช้งานได้ดี หากผู้ใช้ clueless ของคุณสามารถเข้าถึงการกำหนดค่าสำหรับบางสิ่งที่ทำงานในฐานะรูทนั่นเป็นสาเหตุที่หายไปแล้ว
muru

1
@IcyIcyIce ให้ครูของคุณชี้แจงสิ่งที่พวกเขาต้องการ ส่วนหนึ่งของการเรียนรู้เพื่อพัฒนาซอฟต์แวร์คือการทำความเข้าใจข้อกำหนดอย่างชัดเจน
muru

1
@IcyIcyIce ดูการอัปเดต
muru

4

เห็นได้ชัดว่าฉันไม่ใช่bashผู้เชี่ยวชาญที่นี่ แต่แนวคิดไม่ควรแตกต่างในภาษาที่คุณใช้:

ตัวอย่าง

ในตัวอย่างด้านล่างคุณสามารถใช้สคริปต์พื้นฐาน (มาก) เพื่อตั้งค่าสตริงหรือพิมพ์สตริงตามที่กำหนดไว้ในไฟล์ปรับแต่งของคุณ:

#!/bin/bash

# argument to set a new string or print the set string
arg=$1
# possible string as second argument
string=$2
# path to your config file
configfile="$HOME/stringfile"

# if the argument is: "set", write the string (second argument) to a file
if [ "$arg" == "set" ]
then
echo "$string" > $configfile 
# if the argunment is "print": print out the set string, as defined in your file
elif [ "$arg" == "print" ]
then 
echo "$( cat $configfile )"
fi

แล้วก็

  • ในการตั้งค่าสตริงลงในไฟล์ปรับแต่งของคุณ:

    $ '/home/jacob/Bureaublad/test.sh' set "Een aap op een fiets, hoe vind je zoiets?"
  • จากนั้นในการพิมพ์สตริงตามที่กำหนดไว้ใน "configfile" ของคุณ:

    $ '/home/jacob/Bureaublad/test.sh' print
    Een aap op een fiets, hoe vind je zoiets?

แน่นอนในสคริปต์ที่ใช้จริงคุณต้องเพิ่มสิ่งต่าง ๆ มากมายเพื่อให้แน่ใจว่าข้อโต้แย้งนั้นถูกต้องตัดสินใจว่าจะทำอย่างไรเมื่ออินพุตไม่ถูกต้องไฟล์การตั้งค่าไม่มีอยู่ ฯลฯ แต่:

นี่คือแนวคิดพื้นฐาน


ขอบคุณฉันเพิ่งอัปเดตคำถามฉันคิดว่าฉันไม่ได้ทำให้ชัดเจน ... แต่ในกรณีง่าย ๆ นี้จะทำงานเหมือนคาถา ofc
IcyIcyIce

4

ใช้sourceหรือ.เพื่อโหลดไฟล์

source /path/to/file

หรือ

. /path/to/file

เราขอแนะนำให้คุณตรวจสอบว่ามีไฟล์อยู่ก่อนที่จะโหลดหรือไม่เพราะคุณไม่ต้องการเรียกใช้สคริปต์ต่อไปหากไม่มีไฟล์กำหนดค่าอยู่


0

ฉันใช้อันนี้ ...

#!/bin/bash

CFG_FILE=/etc/test.conf
CFG_CONTENT=$(cat $CFG_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g')
eval "$CFG_CONTENT"

ไฟล์ Conf ถูกวิเคราะห์คำด้วย sed แล้วประเมินว่าเป็น asignments ตัวแปรอย่างง่าย

การแยกค่าคีย์ครั้งแรก (รองรับ = ยังล้อมรอบด้วยช่องว่าง)

sed ที่สองลบช่องว่างรอบ = sign สำหรับการจัดตำแหน่งตัวแปรที่ถูกต้อง

การรักษาที่ละเอียดกว่านั้นสามารถเพิ่มได้

ข้อความอื่น ๆ ที่ไม่ตรงกันในไฟล์ conf จะถูกลบออก (รวมถึง # หรือ; ความเห็นและอื่น ๆ )

ระวังว่าคำสั่งเชลล์บรรทัดเดียวสามารถประเมินได้จากไฟล์ปรับแต่งนี้ด้วย!


1
catการใช้งานที่ไร้ประโยชน์ของ ทำไมคุณถึงเรียกsedกลับไปกลับมาสองครั้ง คุณสามารถโยงsedคำสั่งดังนี้:sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g'
David Foerster

นอกจากนี้sedคำสั่งนี้จะสร้างเอาต์พุตว่างสำหรับรายการไฟล์คอนฟิกูเรชันตัวอย่างในคำถาม -1
David Foerster

1
การปรับปรุงอื่นที่เป็นไปได้: ใช้.คำสั่งและการเปลี่ยนเส้นทางกระบวนการแทนตัวแปรชั่วคราวเพื่อเก็บผลลัพธ์ของกระบวนการย่อย:. <(sed ... "$CFG_FILE")
David Foerster

แน่นอนตัวอย่างของฉันใช้คีย์ = ค่าเช่นไฟล์กำหนดค่า มันเป็นการปฏิบัติที่ดีกว่า "คีย์ค่า" ใช้ key = value ตัวอย่างที่ฉันใช้งานได้ ฉันยอมรับการผูกมัดของคำสั่ง sed ของคุณได้ดีกว่า แต่คำสั่งซอร์สคาดว่าไฟล์เพื่อให้เราสามารถใช้: eval $(sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g' "$CFG_FILE")ซึ่งเป็นวิธีที่ดีกว่าที่จะเข้าใจสิ่งที่เกิดขึ้น
ทใน

ใช่.คาดว่าการทดแทนไฟล์และกระบวนการจะถูกขยายเป็นไฟล์ . <(echo echo foo)ทำงานได้ตามที่คาดไว้ใน Bash v4.3.11 ในตัวอย่างเล็ก ๆ มันอาจจะไม่สำคัญ ฉันไม่ควรส่งผ่านหลายกิโลไบต์ผ่านการทดแทนคำสั่ง
David Foerster

0
#------------------------------------------------------------------------------
# parse the ini like $0.$host_name.cnf and set the variables
# cleans the unneeded during after run-time stuff. Note the MainSection
# courtesy of : http://mark.aufflick.com/blog/2007/11/08/parsing-ini-files-with-sed
#------------------------------------------------------------------------------
doParseConfFile(){
    # set a default cnfiguration file
    cnf_file="$run_unit_bash_dir/$run_unit.cnf"

    # however if there is a host dependant cnf file override it
    test -f "$run_unit_bash_dir/$run_unit.$host_name.cnf" \
    && cnf_file="$run_unit_bash_dir/$run_unit.$host_name.cnf"

    # yet finally override if passed as argument to this function
    # if the the ini file is not passed define the default host independant ini file
    test -z "$1" || cnf_file=$1;shift 1;


    test -z "$2" || ini_section=$2;shift 1;
    doLog "DEBUG read configuration file : $cnf_file"
    doLog "INFO read [$ini_section] section from config file"

    # debug echo "@doParseConfFile cnf_file:: $cnf_file"
    # coud be later on parametrized ...
    test -z "$ini_section" && ini_section='MAIN_SETTINGS'

    doLog "DEBUG reading: the following configuration file"
    doLog "DEBUG ""$cnf_file"
    ( set -o posix ; set ) | sort >"$tmp_dir/vars.before"

    eval `sed -e 's/[[:space:]]*\=[[:space:]]*/=/g' \
        -e 's/#.*$//' \
        -e 's/[[:space:]]*$//' \
        -e 's/^[[:space:]]*//' \
        -e "s/^\(.*\)=\([^\"']*\)$/\1=\"\2\"/" \
        < $cnf_file \
        | sed -n -e "/^\[$ini_section\]/,/^\s*\[/{/^[^#].*\=.*/p;}"`

    ( set -o posix ; set ) | sort >"$tmp_dir/vars.after"

    doLog "INFO added the following vars from section: [$ini_section]"
    cmd="$(comm -3 $tmp_dir/vars.before $tmp_dir/vars.after | perl -ne 's#\s+##g;print "\n $_ "' )"
    echo -e "$cmd"
    echo -e "$cmd" >> $log_file
    echo -e "\n\n"
    sleep 1; printf "\033[2J";printf "\033[0;0H" # and clear the screen
}
#eof func doParseConfFile
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.