Cách tốt nhất để đọc một tập tin cấu hình trong bash


23

Cách tốt nhất để đọc một tập tin cấu hình trong bash là gì?
Ví dụ: bạn có tập lệnh và không sẵn sàng điền tất cả cấu hình theo cách thủ công mỗi lần bạn gọi tập lệnh.

Chỉnh sửa 1: Tôi nghĩ rằng tôi đã không làm rõ, vì vậy: điều tôi muốn là ... Tôi có một cấu hình giống như

variable_name value  
variable_name value ...  

và tôi muốn đọc nó Tôi biết tôi chỉ có thể grep nó cho các đối số mà tôi đang tìm kiếm hoặc vì vậy ... nhưng có lẽ có một cách thông minh hơn :)


2
Bạn sẽ phải chỉ ra loại cấu hình bạn muốn nói. Cung cấp một ví dụ.
muru

Xem thêm một câu hỏi tương tự trên Unix & Linux StackExchange.
Michael

Câu trả lời:


38

Như mbiber đã nói, sourcemột tập tin khác. Ví dụ: tệp cấu hình của bạn some.configsẽ là:

var1=val1
var2=val2

Và kịch bản của bạn có thể trông như sau:

#! /bin/bash

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

. /path/to/some.config

echo "$var1" "$var2"

Nhiều tệp trong /etc/defaultthường phục vụ như các tệp cấu hình cho các tập lệnh shell khác theo cách tương tự. Một ví dụ rất phổ biến từ các bài viết ở đây là /etc/default/grub. Tệp này được sử dụng để đặt các tùy chọn cấu hình cho GRUB, vì đây grub-mkconfiglà tập lệnh shell cung cấp cho nó:

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

Nếu bạn thực sự phải xử lý cấu hình của biểu mẫu:

var1 some value 1
var2 some value 2

Sau đó, bạn có thể làm một cái gì đó như:

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

(Bạn cũng có thể làm một cái gì đó giống như eval "$var=$value", nhưng đó là rủi ro hơn nguồn một kịch bản. Bạn vô tình có thể phá vỡ một cách dễ dàng hơn một tập tin nguồn.)


Đó là một cách tuyệt vời, tôi có thể sử dụng khoảng trắng thay thế sed cho "="
IcyIcyIce

1
@IcyIcyIce Chỉ cần không. Tại sao bạn không thể viết nó =ngay từ đầu?
muru

1
@IcyIcyIce Đó là cách nó phải như vậy. Bạn có thể sử dụng mã shell trong các tệp khác nhau trong /etc/default- và chủ yếu là để sử dụng tốt. Nếu người dùng không biết gì của bạn có quyền truy cập vào cấu hình cho một cái gì đó chạy bằng root, thì đó đã là một nguyên nhân bị mất.
muru

1
@IcyIcyIce giúp giáo viên của bạn làm rõ những gì họ muốn. Một phần của việc học để phát triển phần mềm là nhận biết các yêu cầu rõ ràng.
muru

1
@IcyIcyIce xem cập nhật.
muru

4

Rõ ràng, tôi không phải là bashchuyên gia ở đây, nhưng khái niệm không nên khác biệt trong bất kỳ ngôn ngữ nào bạn sử dụng:

Một ví dụ

Trong ví dụ dưới đây, bạn có thể sử dụng tập lệnh cơ bản (rất) để đặt chuỗi hoặc in chuỗi, như được đặt trong tệp cấu hình của bạn:

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

Sau đó

  • Để đặt một chuỗi vào tập tin cấu hình của bạn:

    $ '/home/jacob/Bureaublad/test.sh' set "Een aap op een fiets, hoe vind je zoiets?"
  • Sau đó, để in ra chuỗi, như được định nghĩa trong "configfile" của bạn:

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

Tất nhiên, trong một tập lệnh được áp dụng thực tế, bạn cần thêm rất nhiều nội dung để đảm bảo các đối số là chính xác, quyết định làm gì khi đầu vào không chính xác, tệp cài đặt không tồn tại, v.v.

Đây là ý tưởng cơ bản


cảm ơn, tôi chỉ đang cập nhật câu hỏi mà tôi nghĩ rằng tôi đã không làm cho nó rõ ràng ... nhưng trong những trường hợp đơn giản, nó sẽ hoạt động như một sự quyến rũ của
IcyIcyIce

4

Sử dụng sourcehoặc .để tải trong một tập tin.

source /path/to/file

hoặc là

. /path/to/file

Bạn cũng nên kiểm tra xem tệp có tồn tại trước khi tải không vì bạn không muốn tiếp tục chạy tập lệnh của mình nếu không có tệp cấu hình.


0

Tôi đang sử dụng cái này ...

#!/bin/bash

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

Tệp Conf được phân tích cú pháp với sed và sau đó được đánh giá là các biến số đơn giản

Các giá trị khóa phân tích cú pháp đầu tiên (hỗ trợ cũng = được bao quanh bằng khoảng trắng)

Thứ hai sed loại bỏ khoảng trắng xung quanh = dấu cho phân bổ biến hợp lệ

Điều trị sed xa hơn có thể được thêm vào

Tất cả các văn bản không phù hợp khác trong tệp conf sẽ bị xóa (bao gồm # hoặc; bình luận và khác)

Xin lưu ý rằng các lệnh shell dòng đơn cũng có thể được đánh giá từ tệp cấu hình này!


1
Sử dụng vô dụngcat . Tại sao bạn gọi sedhai lần back-to-back? Bạn có thể xâu chuỗi sedcác lệnh như vậy:sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g'
David Foerster

Ngoài ra, sedlệnh này sẽ tạo ra một đầu ra trống cho các mục nhập tệp cấu hình mẫu trong câu hỏi. -1
David foerster

1
Một cải tiến khác có thể có: sử dụng .lệnh và xử lý chuyển hướng thay vì các biến tạm thời để giữ đầu ra của quy trình phụ:. <(sed ... "$CFG_FILE")
David Foerster

Tất nhiên ví dụ của tôi sử dụng key = value như tập tin cấu hình. Đó là thực hành tốt hơn so với "giá trị quan trọng". Sử dụng key = value ví dụ của tôi hoạt động. Tôi thừa nhận chuỗi lệnh sed của bạn tốt hơn, tôi thừa nhận, nhưng lệnh nguồn mong đợi tệp để chúng ta có thể sử dụng : eval $(sed -r '/[^=]+=[^=]+/!d;s/\s+=\s/=/g' "$CFG_FILE"), đó là cách tốt hơn để hiểu những gì đang diễn ra.
smARTin

Có, .hy vọng một tập tin và quá trình thay thế được mở rộng thành một tập tin. . <(echo echo foo)hoạt động đúng như mong đợi trong Bash v4.3.11. Trong các ví dụ nhỏ có lẽ sẽ không có vấn đề gì. Tôi thà không vượt qua nhiều kilobyte thông qua thay thế lệnh.
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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.