আমার শেল স্ক্রিপ্টের জন্য কনফিগারেশন ফাইলটি ব্যবহার করুন


26

আমার নিজের স্ক্রিপ্টের জন্য একটি কনফিগার ফাইল তৈরি করতে হবে: এখানে একটি উদাহরণ:

লিপি:

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

এর বিষয়বস্তু /home/myuser/test/config:

nam="Mark"
sur="Brown"

এটা কাজ!

আমার প্রশ্ন: এটি কি এটি করার সঠিক উপায় বা অন্য উপায় আছে?


ভেরিয়েবলগুলি শীর্ষে থাকা উচিত। আমি অবাক হয়েছি এটি কাজ করে। যাইহোক, আপনার একটি কনফিগার ফাইল কেন দরকার? আপনি কি এই ভেরিয়েবলগুলি অন্য কোথাও ব্যবহার করার পরিকল্পনা করছেন?
ফাহিম মিঠা

ফাহিম, আমার ভেরিয়েবলগুলি দরকার কারণ আমার স্ক্রিপ্টের অনেকগুলি বিকল্প রয়েছে: একটি কনফিগার ফাইল ব্যবহার করে স্ক্রিপ্টটি বিভক্ত করা হবে। ধন্যবাদ
পোল হ্যালেন

5
আইএমএইচও। আমি এইভাবে করতে হবে।
তিনটি

abcdeএটিও এইভাবে করে এবং এটি বেশ বড় প্রোগ্রাম (শেল স্ক্রিপ্টের জন্য)। আপনি এটি এখানে একবার তাকান করতে পারেন ।
লুকাস

উত্তর:


19

sourceএটি স্বেচ্ছাসেবক কোড কার্যকর করবে বলে নিরাপদ নয় is এটি আপনার পক্ষে উদ্বেগের বিষয় নাও হতে পারে তবে যদি ফাইলের অনুমতিগুলি ভুল হয় তবে কোনও ফাইল-সিস্টেমের অ্যাক্সেসযুক্ত আক্রমণকারীর পক্ষে অন্য কোনও সুরক্ষিত স্ক্রিপ্ট দ্বারা লোড হওয়া কনফিগারেশন ফাইলে কোড ইনজেকশন দিয়ে কোনও সুবিধাযুক্ত ব্যবহারকারী হিসাবে কোড চালানো সম্ভব হয় be init স্ক্রিপ্ট।

এখনও অবধি, আমি যে সর্বোত্তম সমাধানটি সনাক্ত করতে পেরেছি তা হ'ল আনাড়ি পুনর্নবীকরণ-চাকা সমাধান:

myscript.conf

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

ব্যবহার করে source, এটি echo rm -rf /দু'বার চলবে , পাশাপাশি চলমান ব্যবহারকারীর পরিবর্তন করবে $PROMPT_COMMAND। পরিবর্তে, এটি করুন:

myscript.sh (বাশ 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 (ম্যাক / বাশ 3-সামঞ্জস্যপূর্ণ)

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

আপনি যদি আমার কোডটিতে কোনও সুরক্ষা কাজে লাগান তবে দয়া করে জবাব দিন।


1
এফওয়াইআই এটি একটি বাশ সংস্করণ solution.০ সমাধান যা দুর্ভাগ্যক্রমে অ্যাপল দ্বারা আরোপিত উন্মাদ লাইসেন্স সংক্রান্ত বিষয়গুলির অধীন এবং
ম্যাকসে

সুকিমা ভাল পয়েন্ট আমি বাশ 3 এর সাথে সামঞ্জস্যপূর্ণ একটি সংস্করণ যুক্ত করেছি Its এর দুর্বলতা হ'ল এটি *ইনপুটগুলি সঠিকভাবে পরিচালনা করবে না , তবে বাশের মধ্যে কী সেই চরিত্রটি ভালভাবে পরিচালনা করে?
মিক্কেল

পাসওয়ার্ডটিতে ব্যাকস্ল্যাশ থাকলে প্রথম স্ক্রিপ্ট ব্যর্থ হয়।
কুসালানন্দ

@ কুসালানন্দ যদি ব্যাকস্ল্যাশ পালাতে পারে? my\\password
মিক্কেল

10

এখানে একটি পরিষ্কার এবং পোর্টেবল সংস্করণ রয়েছে যা ম্যাক এবং লিনাক্স, উভয়ই বাশ 3 এবং এর সাথে সামঞ্জস্যপূর্ণ।

আপনার সমস্ত শেল স্ক্রিপ্টে বিশাল, বিশৃঙ্খল, নকল "ডিফল্ট" কনফিগার ফাংশনের প্রয়োজন এড়াতে এটি পৃথক ফাইলে সমস্ত ডিফল্ট নির্দিষ্ট করে। এবং এটি আপনাকে ডিফল্ট ফ্যালব্যাকগুলি সহ বা ছাড়াই পঠনগুলির মধ্যে চয়ন করতে দেয়:

config.cfg :

myvar=Hello World

config.cfg.deafults :

myvar=Default Value
othervar=Another Variable

config.shlib (এটি একটি গ্রন্থাগার, সুতরাং কোনও শেবাং-লাইন নেই):

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 (অথবা যে কোনও স্ক্রিপ্ট যেখানে আপনি কনফিগার মানগুলি পড়তে চান) :

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

পরীক্ষার স্ক্রিপ্টের ব্যাখ্যা:

  • নোট করুন যে টেস্ট.শ-এর কনফিগারেশনের সমস্ত ব্যবহার ডাবল কোটে মোড়ানো আছে। প্রতিটি কনফিগার_জেটকে দ্বিগুণ উদ্ধৃতিতে আবদ্ধ করে আমরা নিশ্চিত করে নিই যে ভেরিয়েবলের মানটি পাঠ্যের পতাকা হিসাবে কখনই ভুল ব্যাখ্যা করা হবে না । এবং এটি নিশ্চিত করে যে আমরা সাদা স্থান যথাযথভাবে সংরক্ষণ করি, যেমন কনফিগার মানটিতে এক সারিতে একাধিক স্পেস।
  • এবং printfলাইন কি ? ঠিক আছে, এটি এমন কিছু যা আপনার সম্পর্কে সচেতন হওয়া উচিত: echoপাঠ্য মুদ্রণের জন্য একটি খারাপ কমান্ড যা আপনার নিয়ন্ত্রণ করতে পারে না। এমনকি আপনি ডাবল উদ্ধৃতি ব্যবহার করলেও এটি পতাকাগুলির ব্যাখ্যা করবে। এটিকে myvar(ইন config.cfg) সেট করার চেষ্টা করুন -eএবং আপনি একটি খালি লাইন দেখতে পাবেন, কারণ echoএটি ভাবেন যে এটি একটি পতাকা। কিন্তু printfসমস্যা নেই। printf --"এই, মুদ্রণ এবং পতাকাগুলি হিসাবে কিছু ব্যাখ্যা না" বলেছেন, "%s\n"বলে "একটি trailing রাখুন NEWLINE একটি স্ট্রিং হিসাবে আউটপুট ফরম্যাট, এবং সবশেষে চূড়ান্ত প্যারামিটার ফর্ম্যাটে printf জন্য মান।
  • আপনি পর্দায় মান অনুনাদী করা যাচ্ছে না, তাহলে আপনি কেবল তাদের স্বাভাবিকভাবে দায়িত্ব অর্পণ চাই, মত myvar="$(config_get myvar)";। যদি আপনি এগুলি স্ক্রিনে মুদ্রণ করতে যাচ্ছেন তবে আমি পরামর্শ দিচ্ছি যে ব্যবহারকারী কনফিগারেশনে থাকা কোনও প্রতিধ্বনি-অসামঞ্জস্যপূর্ণ স্ট্রিংয়ের বিরুদ্ধে পুরোপুরি নিরাপদ হয়ে প্রিন্টফ ব্যবহার করুন। তবে প্রতিধ্বনি ঠিক আছে যদি ব্যবহারকারী-প্রদত্ত ভেরিয়েবলটি আপনার প্রতিধ্বনিত স্ট্রিংয়ের প্রথম অক্ষর না হয়, কারণ "ফ্ল্যাগগুলি" ব্যাখ্যা করার জন্য এটিই একমাত্র পরিস্থিতি, তাই echo "foo: $(config_get myvar)";"ফু" না বলে কিছু নিরাপদ থাকে ড্যাশ দিয়ে শুরু করুন এবং তাই প্রতিধ্বনি জানান যে বাকী স্ট্রিং এটির জন্য পতাকাও নয়। :-)

@ user2993656 এটি প্রমাণ করার জন্য ধন্যবাদ যে আমার আসল কোডটিতে এখনও আমার একটি সঠিক কনফিগারেশন ফাইলের নাম (এনভায়রনমেন্ট.এফ.জি.গু) রয়েছে one আপনি যে "ইকো-এন" সম্পাদনা করেছেন, এটি ব্যবহৃত শেলের উপর নির্ভর করে। ম্যাক / লিনাক্স ব্যাশে, "ইকো-এন" এর অর্থ "নতুন লাইনের পিছন ছাড়াই প্রতিধ্বনি", যা আমি নতুন লাইনগুলি অনুসরণ করা এড়াতে করেছি। তবে এটি ছাড়া এটি ঠিক একইরকম কাজ করছে বলে মনে হয়, তাই সম্পাদনার জন্য ধন্যবাদ!
gw0

প্রকৃতপক্ষে, আমি কেবল ইকোটির পরিবর্তে প্রিন্টফ ব্যবহার করার জন্য এটি আবার লিখে দিয়েছি, যা নিশ্চিত করে যে আমরা কনফিগার মানগুলিতে "পতাকা" এর ভুল ব্যাখ্যা করার ঝুঁকি থেকে মুক্তি পাব।
gw0

আমি এই সংস্করণটি সত্যিই পছন্দ করি। আমি config.cfg.defaultsকল করার সময় তাদের সংজ্ঞায়নের পরিবর্তে বাদ দিয়েছিলাম $(config_get var_name "default_value")tritarget.org/static/...
Sukima

7

কনফিগারেশন ফাইলটি পার্স করুন, এটি চালাবেন না।

আমি বর্তমানে কর্মক্ষেত্রে একটি অ্যাপ্লিকেশন লিখছি যা অত্যন্ত সাধারণ এক্সএমএল কনফিগারেশন ব্যবহার করে:

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

শেল স্ক্রিপ্টে ("অ্যাপ্লিকেশন"), ব্যবহারকারীর নামটি পেতে আমি এটিই করি (কম-বেশি, আমি এটি শেল ফাংশনটিতে রেখেছি):

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

xmlকমান্ড XMLStarlet , যা সর্বাধিক Unices জন্য উপলব্ধ।

আমি এক্সএমএল ব্যবহার করছি যেহেতু অ্যাপ্লিকেশনটির অন্যান্য অংশগুলিও এক্সএমএল ফাইলগুলিতে এনকোড করা ডেটা নিয়ে কাজ করে, তাই এটি সবচেয়ে সহজ ছিল।

আপনি যদি JSON পছন্দ করেন তবে jqশেল JSON পার্সার ব্যবহার করা সহজ there's

আমার কনফিগারেশন ফাইলটি JSON এ এর ​​মতো দেখতে লাগবে:

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

এবং তারপরে আমি স্ক্রিপ্টে ব্যবহারকারীর নামটি পেয়ে যাব:

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

স্ক্রিপ্টটি কার্যকর করাতে অনেকগুলি সুবিধা এবং অসুবিধা রয়েছে। প্রধান অসুবিধাগুলি হ'ল সুরক্ষা, যদি কেউ কনফিগার ফাইলটি পরিবর্তন করতে পারে তবে তারা কোড সম্পাদন করতে পারে, এবং এটি নির্বোধ প্রমাণ করা আরও শক্ত। সুবিধার গতি হ'ল, একটি সাধারণ পরীক্ষায় পিকিউ চালানোর চেয়ে কনফিগার ফাইলের উত্স তুলনায় 10,000 গুণ বেশি দ্রুত এবং নমনীয়তা, যে কেউ বানর প্যাচিং অজগর পছন্দ করে এটি প্রশংসা করবে।
আইক্রাস

@ আইক্রাস আপনি সাধারণত কত বড় কনফিগারেশন ফাইলগুলির মুখোমুখি হন এবং একটি সেশনে আপনার কতবার পার্স করার প্রয়োজন হয়? এটিও লক্ষ্য করুন যে এক সাথে একাধিক মান XML বা JSON এর বাইরে থাকতে পারে।
কুসালানন্দ

সাধারণত কয়েকটি (1 থেকে 3) মান। আপনি যদি evalএকাধিক মান সেট করতে ব্যবহার করেন তবে আপনি কনফিগার ফাইলের নির্বাচিত অংশগুলি সম্পাদন করছেন :-)।
আইক্রাস

1
@ আইক্রাস আমি অ্যারে ভাবছিলাম ... কোনও evalকিছুর দরকার নেই। বিদ্যমান পার্সার (যদিও এটি একটি বাহ্যিক ইউটিলিটি) এর সাথে মানক ফর্ম্যাট ব্যবহার করার পারফরম্যান্স হিট দৃust়তা, কোডের পরিমাণ, ব্যবহারের সহজতা এবং রক্ষণাবেক্ষণের তুলনায় তুলনামূলকভাবে নগণ্য।
কুসালানন্দ

1
"কনফিগার ফাইলটি পার্স করুন, এটি
চালাবেন

4

সর্বাধিক সাধারণ, দক্ষ ও সঠিক উপায় হ'ল ব্যবহার করা sourceবা .শর্টহ্যান্ড ফর্ম হিসাবে। উদাহরণ স্বরূপ:

source /home/myuser/test/config

অথবা

. /home/myuser/test/config

অতিরিক্ত বিবেচনা করার মতো কিছু বিষয়, অতিরিক্ত কোড সন্নিবেশ করা যেতে পারে এমন একটি অতিরিক্ত বাহ্যিক-উত্সযুক্ত কনফিগারেশন ফাইল ব্যবহার করে উত্থাপন করা যেতে পারে। এই সমস্যাটি কীভাবে সনাক্ত এবং সমাধান করা যায় সে সম্পর্কে আরও তথ্যের জন্য, আমি http://wiki.bash-hackers.org/howto/conffile#secure_it এর 'এটি সুরক্ষিত করুন' বিভাগটি একবার দেখার পরামর্শ দিচ্ছি


5
আমার এই নিবন্ধটি সম্পর্কে উচ্চ আশা ছিল (আমার অনুসন্ধানের ফলাফলগুলিতেও উঠে এসেছিল) তবে লেখক যে ক্ষতিকারক কোডটি ফিল্টার করতে রেগেক্স ব্যবহার করার চেষ্টা করার পরামর্শ দিয়েছেন তা নিরর্থকতার একটি অনুশীলন।
মিক্কেল

বিন্দু সহ পদ্ধতিটির জন্য একটি নিখুঁত পথ প্রয়োজন? আপেক্ষিকটির সাথে এটি কাজ করে না
ডেভিড

2

আমি এটি আমার স্ক্রিপ্টগুলিতে ব্যবহার করি:

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
}

প্রতিটি চরিত্রের সংমিশ্রণকে সমর্থন করা উচিত, বাদে কীগুলি থাকতে পারে না =, কারণ এটিই পৃথক that's অন্য কিছু কাজ করে।

% 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

এছাড়াও, এটি সম্পূর্ণ নিরাপদ যেহেতু এটি কোনও ধরণের source/ ব্যবহার করে নাeval


0

আমার দৃশ্যের জন্য, sourceবা ভাল .ছিল, তবে আমি FOO=bar myscript.shকনফিগার করা ভেরিয়েবলের চেয়ে প্রাধান্য গ্রহণ করে স্থানীয় পরিবেশের ভেরিয়েবলগুলি (যেমন, ) সমর্থন করতে চেয়েছিলাম । আমিও চেয়েছিলাম যে কনফিগারেশন ফাইলটি ব্যবহারকারীর পক্ষে সম্পাদনাযোগ্য এবং স্বাচ্ছন্দযুক্ত কনফিগার ফাইলগুলির জন্য স্বাচ্ছন্দ্যময় হোক এবং এটিকে যতটা সম্ভব ছোট / সরল রাখুন, যাতে আমার খুব ছোট স্ক্রিপ্টের মূল জোড় থেকে বিক্ষিপ্ত না হয়।

এটিই আমি নিয়ে এসেছি:

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)

মূলত - এটি ভেরিয়েবল সংজ্ঞা পরীক্ষা করে (হোয়াইটস্পেস সম্পর্কে খুব নমনীয় না হয়ে) যাচাই করে এবং সেই লাইনগুলি পুনরায় লেখায় যাতে ভ্যারিয়েবলের জন্য মানটি একটি ডিফল্টে রূপান্তরিত হয় এবং ভেরিয়েবলটি যদি XDG_CONFIG_HOMEউপরের ভেরিয়েবলের মতো পাওয়া যায় তবে অবিরাম পরিবর্তন হয় । এটি কনফিগার ফাইলের পরিবর্তিত সংস্করণ সূত্র ধরে চালিয়ে যায়।

ভবিষ্যতের কাজ sedস্ক্রিপ্টটিকে আরও শক্তিশালী করে তুলতে পারে , লাইনগুলিকে অদ্ভুত বলে মনে হয় বা সংজ্ঞা নয়, এমন লাইনগুলি ফিল্টার করে দেয়, লাইন মন্তব্যগুলির শেষে ভাঙতে পারে না - তবে এটি আপাতত আমার পক্ষে যথেষ্ট good


0

এটি সংক্ষিপ্ত এবং সুরক্ষিত:

# 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নিশ্চিত আপনি শুধুমাত্র থেকে ভেরিয়েবল পেতেcommon.vars


আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.