আমি কেবল একটি পার্সার লিখেছিলাম যে আমি ইয়ে বলে! ( ইয়ামল ইয়ামলেস্কে নয়! ) যা ইয়ামএলএসকে , পার্স করে যা YAML এর একটি ছোট উপসেট। সুতরাং, আপনি যদি বাশের জন্য 100% অনুগত YAML পার্সার খুঁজছেন তবে এটি নয়। তবে ওপিকে উদ্ধৃত করার জন্য, আপনি যদি কোনও কাঠামোগত কনফিগারেশন ফাইল চান যা কোনও অ প্রযুক্তিগত ব্যবহারকারীর পক্ষে ওয়াইএএমএল -র মতো সম্পাদনা করা সম্ভব হয় তবে এটি আগ্রহী হতে পারে।
এটি পূর্ববর্তী উত্তরের দ্বারা অনুপ্রাণিত হয়েছে তবে বেসিক ভেরিয়েবলের পরিবর্তে সম্মিলিত অ্যারেগুলি ( হ্যাঁ, এটি বাশ 4.x প্রয়োজন ) লিখেছেন । এটি এমনভাবে হয় যাতে কীগুলি সম্পর্কে পূর্বের জ্ঞান ছাড়াই ডেটা পার্স করার অনুমতি দেয় যাতে ডেটা চালিত কোড লেখা যায়।
কী / মান অ্যারের উপাদানগুলির পাশাপাশি, প্রতিটি অ্যারেতে keys
কীগুলির নামের সাথে একটি children
অ্যারে থাকে, শিশু অ্যারের নামের একটি অ্যারে থাকে এবং একটি parent
কী থাকে যা তার পিতামাতাকে বোঝায়।
এটি ইয়ামলেসকের উদাহরণ:
root_key1: this is value one
root_key2: "this is value two"
drink:
state: liquid
coffee:
best_served: hot
colour: brown
orange_juice:
best_served: cold
colour: orange
food:
state: solid
apple_pie:
best_served: warm
root_key_3: this is value three
এটি কীভাবে ব্যবহার করবেন তা এখানে একটি উদাহরণ রয়েছে:
#!/bin/bash
# An example showing how to use Yay
. /usr/lib/yay
# helper to get array value at key
value() { eval echo \${$1[$2]}; }
# print a data collection
print_collection() {
for k in $(value $1 keys)
do
echo "$2$k = $(value $1 $k)"
done
for c in $(value $1 children)
do
echo -e "$2$c\n$2{"
print_collection $c " $2"
echo "$2}"
done
}
yay example
print_collection example
কোন ফলাফল:
root_key1 = this is value one
root_key2 = this is value two
root_key_3 = this is value three
example_drink
{
state = liquid
example_coffee
{
best_served = hot
colour = brown
}
example_orange_juice
{
best_served = cold
colour = orange
}
}
example_food
{
state = solid
example_apple_pie
{
best_served = warm
}
}
এবং এখানে আছে পার্সার:
yay_parse() {
# find input file
for f in "$1" "$1.yay" "$1.yml"
do
[[ -f "$f" ]] && input="$f" && break
done
[[ -z "$input" ]] && exit 1
# use given dataset prefix or imply from file name
[[ -n "$2" ]] && local prefix="$2" || {
local prefix=$(basename "$input"); prefix=${prefix%.*}
}
echo "declare -g -A $prefix;"
local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
sed -n -e "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
-e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$input" |
awk -F$fs '{
indent = length($1)/2;
key = $2;
value = $3;
# No prefix or parent for the top level (indent zero)
root_prefix = "'$prefix'_";
if (indent ==0 ) {
prefix = ""; parent_key = "'$prefix'";
} else {
prefix = root_prefix; parent_key = keys[indent-1];
}
keys[indent] = key;
# remove keys left behind if prior row was indented more than this row
for (i in keys) {if (i > indent) {delete keys[i]}}
if (length(value) > 0) {
# value
printf("%s%s[%s]=\"%s\";\n", prefix, parent_key , key, value);
printf("%s%s[keys]+=\" %s\";\n", prefix, parent_key , key);
} else {
# collection
printf("%s%s[children]+=\" %s%s\";\n", prefix, parent_key , root_prefix, key);
printf("declare -g -A %s%s;\n", root_prefix, key);
printf("%s%s[parent]=\"%s%s\";\n", root_prefix, key, prefix, parent_key);
}
}'
}
# helper to load yay data file
yay() { eval $(yay_parse "$@"); }
লিঙ্কযুক্ত উত্স ফাইলে কিছু ডকুমেন্টেশন রয়েছে এবং নীচে কোডটি কী করে তার একটি সংক্ষিপ্ত ব্যাখ্যা।
yay_parse
ফাংশন প্রথম অবস্থান নির্ণয় করে input
ফাইল বা 1. পরবর্তী একটি প্রস্থান স্থিতি সহ প্রস্থান করে, এটা ডেটা সেটটি নির্ধারণ করে prefix
, হয় স্পষ্টভাবে নির্দিষ্ট ফাইলের নাম থেকে উদ্ভূত।
এটি bash
এর স্ট্যান্ডার্ড আউটপুটে বৈধ কমান্ড লিখেছে যা কার্যকর করা হলে ইনপুট ডেটা ফাইলের বিষয়বস্তু উপস্থাপন করে অ্যারেগুলি সংজ্ঞায়িত করে। এর মধ্যে প্রথমটি শীর্ষ স্তরের অ্যারে সংজ্ঞায়িত করে:
echo "declare -g -A $prefix;"
দ্রষ্টব্য যে অ্যারে ঘোষণাগুলি সম্মিলিত ( -A
) যা বাশ সংস্করণ 4 এর বৈশিষ্ট্য Dec ঘোষণাগুলিও বৈশ্বিক ( -g
) তাই কোনও ফাংশনে এগুলি কার্যকর করা যেতে পারে তবে সহায়িকার মতো বৈশ্বিক সুযোগে উপলভ্য হতে পারে yay
:
yay() { eval $(yay_parse "$@"); }
ইনপুট ডেটা শুরুতে প্রক্রিয়া করা হয় sed
। এটি এমন লাইনগুলি ড্রপ করে যা এএসসিআইআই ফাইল পৃথককারী চরিত্রের সাথে বৈধ ইয়ামলেস্কে ক্ষেত্রগুলি সীমিত করার আগে এবং মান ক্ষেত্রের আশেপাশের কোনও ডাবল-কোটস সরিয়ে নেওয়ার আগে ইয়ামলেস্ক বিন্যাসের স্পেসিফিকেশনের সাথে মেলে না ।
local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
sed -n -e "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
-e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$input" |
দুটি এক্সপ্রেশন একই; এগুলির ক্ষেত্রে কেবল আলাদা হয় কারণ প্রথমটি উদ্ধৃত মানগুলি খুঁজে বের করে যেখানে দ্বিতীয়টি অনাবৃত মানগুলি খুঁজে বের করে।
ফাইল পৃথককারী (28 / হেক্স 12 / অকট্যাল 034), কারণ একটি মুদ্রণযোগ্য নয় এমন অক্ষর হিসেবে, এটা ইনপুট ডেটা হতে করার সম্ভাবনা কম ব্যবহার করা হয়।
ফলাফলটি পাইপ করা হয় awk
যা একবারে তার ইনপুটকে এক লাইনে প্রসেস করে। এটি প্রতিটি ক্ষেত্রকে একটি ভেরিয়েবলের জন্য নির্ধারণ করতে FS অক্ষর ব্যবহার করে :
indent = length($1)/2;
key = $2;
value = $3;
সমস্ত লাইনের একটি ইনডেন্ট (সম্ভবত শূন্য) এবং একটি কী রয়েছে তবে সেগুলির সমস্তটির কোনও মূল্য নেই। এটি প্রথম ক্ষেত্রের দৈর্ঘ্যকে বিভাজক রেখার জন্য একটি ইনডেন্ট স্তরকে গণনা করে, যার মধ্যে নেতৃস্থানীয় সাদা স্থান দুটি রয়েছে। কোনও ইনডেন্ট ছাড়াই শীর্ষ স্তরের আইটেমগুলি ইনডেন্ট স্তর শূন্যে থাকে।
পরবর্তী, এটি prefix
বর্তমান আইটেমটির জন্য কী ব্যবহার করতে হবে তা কার্যকর করে। একটি অ্যারের নাম তৈরি করার জন্য এটি কী কীতে যুক্ত হয়। root_prefix
শীর্ষ স্তরের অ্যারের জন্য একটি রয়েছে যা ডেটা সেট নাম এবং আন্ডারস্কোর হিসাবে সংজ্ঞায়িত হয়:
root_prefix = "'$prefix'_";
if (indent ==0 ) {
prefix = ""; parent_key = "'$prefix'";
} else {
prefix = root_prefix; parent_key = keys[indent-1];
}
parent_key
বর্তমান লাইন এর ইন্ডেন্ট স্তরের উপরে ইন্ডেন্ট পর্যায়ে চাবিকাঠি এবং সংগ্রহ যা বর্তমান লাইন অংশ প্রতিনিধিত্ব করে। সংগ্রহের কী / মান জোড়গুলি একটি অ্যারেতে সংরক্ষণ করা হবে যার নাম prefix
এবং এর সংক্ষিপ্তকরণ হিসাবে সংজ্ঞায়িত করা হয়েছে parent_key
।
শীর্ষ স্তরের (ইনডেন্ট স্তর শূন্য) জন্য ডেটা সেট উপসর্গটি প্যারেন্ট কী হিসাবে ব্যবহৃত হয় সুতরাং এর কোনও উপসর্গ নেই (এটি সেট করা আছে ""
)। অন্যান্য সমস্ত অ্যারে মূল উপসর্গ সহ উপস্থাপিত হয়।
এরপরে, বর্তমান কীটি কী (বিশদ-অভ্যন্তরীণ) অ্যারেতে sertedোকানো হয়েছে। এই অ্যারে পুরো অজস্র অধিবেশন জুড়ে থাকে এবং তাই পূর্ববর্তী লাইনে সন্নিবেশ করা কীগুলি রয়েছে। কীটি অ্যারের সূচক হিসাবে এর ইনডেন্টটি ব্যবহার করে অ্যারেতে প্রবেশ করানো হয়।
keys[indent] = key;
যেহেতু এই অ্যারেটিতে পূর্ববর্তী লাইনগুলি থেকে কী রয়েছে, বর্তমান লাইনের ইনডেন্ট স্তরের চেয়ে কোনও ইনডেন্ট স্তর গ্রেটারের সাথে থাকা কীগুলি সরানো হয়েছে:
for (i in keys) {if (i > indent) {delete keys[i]}}
এটি মূল লাইন 0 থেকে বর্তমান লাইনে মূল-শৃঙ্খলযুক্ত কী-অ্যারেটি ছেড়ে দেয়। পূর্বের লাইনটি বর্তমান লাইনের চেয়ে আরও গভীর ইনডেন্ট করা অবস্থায় থাকা বাকী কীগুলি সরিয়ে দেয়।
চূড়ান্ত বিভাগটি bash
কমান্ডগুলি আউটপুট করে : মান ব্যতীত একটি ইনপুট লাইন একটি নতুন ইনডেন্ট স্তর ( ওয়াইএএমএল পার্লেন্সে একটি সংগ্রহ ) আরম্ভ করে এবং একটি মান সহ একটি ইনপুট লাইন বর্তমান সংগ্রহটিতে একটি কী যুক্ত করে।
সংগ্রহের নামটি বর্তমান লাইনের prefix
এবং এর সংক্ষেপণ parent_key
।
যখন একটি কীটির একটি মান থাকে, তখন সেই মান সহ একটি কীটি বর্তমান সংগ্রহকে এইভাবে বরাদ্দ করা হয়:
printf("%s%s[%s]=\"%s\";\n", prefix, parent_key , key, value);
printf("%s%s[keys]+=\" %s\";\n", prefix, parent_key , key);
প্রথম বিবৃতিটি চাবিটির নাম অনুসারে কোনও এসোসিয়েটিভ অ্যারে উপাদানটির জন্য মূল্য নির্ধারণের জন্য কমান্ডকে আউটপুট দেয় এবং দ্বিতীয়টি সংগ্রহের স্পেস-সীমাবদ্ধ keys
তালিকায় কী যুক্ত করতে কমান্ডকে আউটপুট দেয় :
<current_collection>[<key>]="<value>";
<current_collection>[keys]+=" <key>";
যখন কোনও কীটির কোনও মান থাকে না, একটি নতুন সংগ্রহ এইভাবে শুরু হয়:
printf("%s%s[children]+=\" %s%s\";\n", prefix, parent_key , root_prefix, key);
printf("declare -g -A %s%s;\n", root_prefix, key);
প্রথম বিবৃতিটি বর্তমানের সংগ্রহের স্থান-সীমিত children
তালিকায় নতুন সংগ্রহ যুক্ত করার কমান্ডকে আউটপুট দেয় এবং দ্বিতীয়টি নতুন সংগ্রহের জন্য একটি নতুন সহযোগী অ্যারে ঘোষণা করার আদেশকে আউটপুট করে:
<current_collection>[children]+=" <new_collection>"
declare -g -A <new_collection>;
এর সমস্ত আউটপুট yay_parse
বাশ eval
বা source
বিল্ট-ইন কমান্ড দ্বারা বাশ কমান্ড হিসাবে পার্স করা যায় ।