কীভাবে পার্শ করবেন এবং ইনআই ফাইলটিকে ব্যাশ অ্যারে ভেরিয়েবলগুলিতে রূপান্তর করবেন?


13

আমি ইনআই ফাইলটিকে ব্যাশ অ্যারে ভেরিয়েবলগুলিতে রূপান্তর করার চেষ্টা করছি। নমুনা আইএনআই নীচে হিসাবে রয়েছে:

[foobar]
session=foo
path=/some/path

[barfoo]
session=bar
path=/some/path

সুতরাং এগুলি হয়ে:

session[foobar]=foo
path[foobar]=/some/path
session[barfoo]=bar

ইত্যাদি।

এই মুহুর্তে, আমি কেবল এই আদেশটি দিয়ে আসতে পারি

awk -F'=' '{ if ($1 ~ /^\[/) section=$1; else if ($1 !~ /^$/) print $1 section "=" $2 }'

এছাড়াও, আরেকটি সমস্যা হ'ল, এটি স্থান =বিবেচনায় নিয়ে আসে না । আমি মনে করি sedসম্ভবত ভাল এই কাজের জন্য উপযুক্ত হয় কিন্তু আমি কিভাবে রাখা জানি এবং অধ্যায় নামের জন্য একটি অস্থায়ী পরিবর্তনশীল সঞ্চয় করবেন না sed

সুতরাং কোন ধারণা কিভাবে এটি করতে?


এটি করার জন্য যদি অন্য কোনও কার্যকর উপায় থাকে তবে আপনার সমাধানটিও নির্দ্বিধায় পোস্ট করুন :)
ফ্লিন্ট


সহজ সমাধানের জন্য, পরীক্ষা করুন: আমি কীভাবে শেল স্ক্রিপ্টের মধ্যে একটি INI মান গ্রহন করব? স্ট্যাকওভারফ্লো এসই তে
কেনরব

উত্তর:


10

গাওক মাঠের সীমানা হিসাবে নিয়মিত প্রকাশগুলি গ্রহণ করে। নিম্নলিখিতটি সমান চিহ্নের চারপাশে ফাঁকা স্থানগুলি সরিয়ে দেয় তবে এগুলি বাকী রেখায় সংরক্ষণ করে। মানটির আশেপাশে উদ্ধৃতি যুক্ত করা হয় যাতে ব্যাশ কার্য সম্পাদন করার সময় সেই স্পেসগুলি যদি থাকে তবে সংরক্ষণ করা হয়। আমি ধরে নিচ্ছি যে বিভাগটির নামগুলি সংখ্যাসূচক হবে, তবে আপনি যদি ব্যাশ 4 ব্যবহার করেন তবে বিভাগের নামগুলি সূচক হিসাবে তাদের সাথে সহযোগী অ্যারেগুলি ব্যবহার করতে এটির সাথে খাপ খাইয়ে নেওয়া সহজ হবে।

awk -F ' *= *' '{ if ($1 ~ /^\[/) section=$1; else if ($1 !~ /^$/) print $1 section "=" "\"" $2 "\"" }'

নোট করুন যে আপনি খালিদ যে স্পেস রিমুভেশনটি প্রদর্শন করতে চান তা (কেবলমাত্র $ 1 এবং বিভাগে) করতে পারেন যেহেতু বাশ ভেরিয়েবলের নামগুলিতে স্পেস থাকতে পারে না।

এছাড়াও, মানগুলিতে সমান চিহ্ন থাকলে এই পদ্ধতিটি কাজ করবে না।

আরেকটি কৌশল while readহ'ল বাশ লুপ ব্যবহার করা এবং ফাইলটি পড়ার সাথে সাথে অ্যাসাইনমেন্টগুলি সম্পাদন করা, declareযা ব্যবহার করে বেশিরভাগ দূষিত সামগ্রী থেকে নিরাপদ।

foobar=1
barfoo=2  # or you could increment an index variable each time a section is found
while IFS='= ' read var val
do
    if [[ $var == \[*] ]]
    then
        section=$var
    elif [[ $val ]]
    then
        declare "$var$section=$val"
    fi
done < filename

আবার, সহযোগী অ্যারেগুলি মোটামুটি সহজেই সমর্থন করা যায়।


1
খুব সুন্দর তথ্য এবং আমি বিশেষত দ্বিতীয় কৌশলটি পছন্দ করি কারণ এটি বাহ্যিক কমান্ডের উপর নির্ভর না করে ফাংশনে অন্তর্নির্মিত ব্যাশ ব্যবহার করে।
ঝাঁকুনি

@ টনিবারগানস্কি: এটিকে একে অপরকে পাইপের পরিবর্তে একটি AWK কলে পরিবর্তন করা যেতে পারে।
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

10

আমি এই কাজের জন্য সাধারণ পাইথন স্ক্রিপ্টটি ব্যবহার করব যেহেতু এটি আইএনআই পার্সারে তৈরি করেছে :

#!/usr/bin/env python

import sys, ConfigParser

config = ConfigParser.ConfigParser()
config.readfp(sys.stdin)

for sec in config.sections():
    print "declare -A %s" % (sec)
    for key, val in config.items(sec):
        print '%s[%s]="%s"' % (sec, key, val)

এবং তারপরে ব্যাশে:

#!/bin/bash

# load the in.ini INI file to current BASH - quoted to preserve line breaks
eval "$(cat in.ini  | ./ini2arr.py)"

# test it:
echo ${barfoo[session]}

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


3
4.2 এর আগে বাশ সংস্করণগুলিতে এটি পূরণের আগে একটি সহযোগী অ্যারে ঘোষণা করা প্রয়োজন, যেমনprint "declare -A %s" % (sec)
ফেলিক্স ইভ


3

যদি আপনি অতিরিক্ত স্থানগুলি মুছে ফেলতে চান তবে আপনি অন্তর্নির্মিত ফাংশনটি ব্যবহার করতে পারেন gsub। উদাহরণস্বরূপ, আপনি যোগ করতে পারেন:

gsub(/ /, "", $1);

এটি সমস্ত স্থান সরিয়ে ফেলবে। আপনি যদি টোকেনের শুরুতে বা শেষে স্পেসগুলি সরাতে চান তবে আপনি এটি ব্যবহার করতে পারেন

gsub(/^ /, "", $1);
gsub(/ $/, "", $1);

কুল কৌশল। এমন কোনও অন্তর্নির্মিত ফাংশনটি
ফ্লিন্ট

0

এখানে একটি খাঁটি বাশ সমাধান।

এটি চিলডেক্স যা পোস্ট করেছে তার একটি নতুন এবং উন্নত সংস্করণ:

https://github.com/albfan/bash-ini-parser

প্রাথমিক উদাহরণ অনুসরণ করা সত্যিই সহজ: আপনি এটি ডাউনলোড করার পরে কেবল ফাইলগুলি bash-ini-parserএবং scripts/file.iniএকই ডিরেক্টরিতে অনুলিপি করুন , তারপরে আমি সেই একই ডিরেক্টরিতে নীচে সরবরাহ করেছি উদাহরণ ব্যবহার করে একটি ক্লায়েন্ট পরীক্ষা স্ক্রিপ্ট তৈরি করুন।

source ./bash-ini-parser
cfg_parser "./file.ini"
cfg_section_sec2
echo "var2=$var2"
echo "var5[*]=${var5[*]}"
echo "var5[1]=${var5[1]}"

বাশ-ইন-পার্সার স্ক্রিপ্টে আমি আরও কিছু উন্নতি এখানে করেছি ...

আপনি যদি উইন্ডোজ লাইনের সমাপ্তির পাশাপাশি ইউনিক্সের সাথে ইনআই ফাইলগুলি পড়তে সক্ষম হতে চান তবে ফাইলটি পড়ার সাথে সাথেই এই লাইনটি সিএফজি_পারসার ফাংশনে যুক্ত করুন:

ini=$(echo "$ini"|tr -d '\r') # remove carriage returns

যদি আপনি এমন ফাইলগুলি পড়তে চান যাগুলিতে সীমাবদ্ধ অ্যাক্সেসের অনুমতি রয়েছে তবে এই alচ্ছিক ফাংশনটি যুক্ত করুন:

# Enable the cfg_parser to read "locked" files
function sudo_cfg_parser {

    # Get the file argument
    file=$1

    # If not "root", enable the "sudo" prefix
    sudoPrefix=
    if [[ $EUID -ne 0 ]]; then sudoPrefix=sudo; fi

    # Save the file permissions, then "unlock" the file
    saved_permissions=$($sudoPrefix stat -c %a $file)
    $sudoPrefix chmod 777 $file

    # Call the standard cfg_parser function
    cfg_parser $file

    # Restore the original permissions
    $sudoPrefix chmod $saved_permissions $file  
}

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

@ রিচলভ ওকে। আমি ভোটের নীচের ব্যাখ্যাটির প্রশংসা করি। তবে, এটি এর একটি সামান্য অংশ, যা সামগ্রিকভাবে প্রশ্নের উত্তর দেওয়া পর্যন্ত ন্যূনতম তাত্পর্যপূর্ণ। "উত্তর" লিঙ্কটি: github.com/albfan/bash-ini-parser । ইতিমধ্যে সম্পূর্ণরূপে ভোট দেওয়ার পরিবর্তে, ইতিমধ্যে optionচ্ছিক মোড়ক ফাংশনের লেবেলযুক্ত এমনটির জন্য আপনি একটি সম্পাদনার পরামর্শ দিতে পারেন।
বুভিনে

0

সর্বদা পাইথনের কনফিগার পার্সারটিকে আশেপাশে রেখে ধরে নেওয়া, যে কোনও এটির মতো শেল সহায়ক ফাংশন তৈরি করতে পারে:

get_network_value()
{
    cat <<EOF | python
import ConfigParser
config = ConfigParser.ConfigParser()
config.read('network.ini')
print (config.get('$IFACE','$param'))
EOF
}

$IFACEএবং $paramঅনুচ্ছেদটি যথাক্রমে পরামিতি।

এই সহায়ক তখন কলগুলি যেমন:

address=`param=address get_network_value` || exit 1
netmask=`param=netmask get_network_value` || exit 1
gateway=`param=gateway get_network_value` || exit 1

আশাকরি এটা সাহায্য করবে!


0

আপনার কাছে গিট উপলভ্য থাকলে এবং মূল নামগুলিতে আন্ডারস্কোর ব্যবহার করতে না পারার সীমাবদ্ধতার সাথে যদি আপনি ঠিক থাকেন তবে আপনি git configসাধারণ উদ্দেশ্যে INI পার্সার / সম্পাদক হিসাবে ব্যবহার করতে পারেন ।

এটি কী / মান জুটির চারপাশ থেকে পার্সিং পরিচালনা করবে =এবং তুচ্ছ শ্বেতস্পেস ফেলে দেবে, এবং আপনি মন্তব্যগুলি পাবেন ( ;এবং উভয় #) এবং মূলত বিনামূল্যে জোর করে লিখুন। আমি .iniনীচে নীচে ওপি'র ইনপুট এবং পছন্দসই আউটপুট (ব্যাশ এসোসিয়েটিভ অ্যারে) এর জন্য একটি সম্পূর্ণ কার্যকারী উদাহরণ অন্তর্ভুক্ত করেছি ।

যাইহোক, একটি কনফিগার ফাইল দেওয়া

; mytool.ini
[section1]
    inputdir = ~/some/dir
    enablesomefeature = true
    enablesomeotherfeature = yes
    greeting = Bonjour, Monde!

[section2]
    anothersetting = 42

… তবে আপনার কেবলমাত্র একটি দ্রুত এবং নোংরা সমাধানের প্রয়োজন হয় এবং বাশ সহযোগী অ্যারেটিতে সেটিংস থাকার ধারণার সাথে আপনি বিবাহিত না হয়ে থাকেন, আপনি যতটা সামান্য ছাড়িয়ে যেতে পারেন:

eval $(git config -f mytool.ini --list | tr . _)

# or if 'eval' skeeves you out excessively
source <(git config -f mytool.ini --list | tr . _)

যা sectionname_variablenameবর্তমান পরিবেশে পরিবেশগত ভেরিয়েবল তৈরি করে । এটি অবশ্যই কাজ করে যদি আপনি বিশ্বাস করতে পারেন যে আপনার মানগুলির কোনওটিতেই কোনও সময়কাল বা শ্বেত স্পেস থাকবে না (আরও শক্তিশালী সমাধানের জন্য নীচে দেখুন)।

অন্যান্য সহজ উদাহরণ

টাইপিং সংরক্ষণে শেল ফাংশন ব্যবহার করে স্বেচ্ছাসেবী মানগুলি আনা হচ্ছে:

function myini() { git config -f mytool.ini; }

এখানে একটি নামও ঠিক আছে, তবে এটি শেল স্ক্রিপ্টে সাধারণত প্রসারিত হয় না [ 1 ], এবং যাইহোক যাই হোক না কেন বাশ ম্যান পৃষ্ঠা অনুসারে , "প্রায় প্রতিটি উদ্দেশ্যেই," [ ] শেল ফাংশন দ্বারা উপন্যাসকে বহিষ্কার করা হয় ।

myini --list
# result:
# section1.inputdir=~/some/dir
# section1.enablesomefeature=true
# section1.enablesomeotherfeature=yes
# section2.anothersetting=42

myini --get section1.inputdir
# result:
# ~/some/dir

সঙ্গে --typeবিকল্প, আপনি যা করতে পারেন "canonicalize" হিসাবে ইন্টিজার, Booleans, অথবা পাথ (স্বয়ংক্রিয়ভাবে বিস্তৃত নির্দিষ্ট সেটিংস ~):

myini --get --type=path section1.inputdir  # value '~/some/dir'
# result:
# /home/myuser/some/dir

myini --get --type=bool section1.enablesomeotherfeature  # value 'yes'
# result:
# true

সামান্য আরও শক্তিশালী দ্রুত এবং নোংরা উদাহরণ

বর্তমান পরিবেশের mytool.iniমতো সমস্ত ভেরিয়েবলগুলি SECTIONNAME_VARIABLENAMEকী মানগুলিতে অভ্যন্তরীণ সাদা স্থান সংরক্ষণ করে উপলভ্য করুন :

source <(
    git config -f mytool.ini --list \
      | sed 's/\([^.]*\)\.\(.*\)=\(.*\)/\U\1_\2\E="\3"/'
)

সেড এক্সপ্রেশনটি ইংরেজিতে কী করছে is

  1. একটি পিরিয়ড অবধি অ-পিরিয়ড অক্ষরগুলির একগুচ্ছ সন্ধান করা \1, তখনকার মতো মনে রাখা
  2. সমান চিহ্ন পর্যন্ত অক্ষরের গুচ্ছ সন্ধান করা, এটি হিসাবে \2এবং মনে রাখা
  3. সমান চিহ্ন হিসাবে সমস্ত অক্ষর সন্ধান করা \3
  4. পরিশেষে, প্রতিস্থাপন স্ট্রিং মধ্যে
    • বিভাগটির নাম + ভেরিয়েবলের নাম হ'ল আপার-কেসড এবং
    • মান অংশটি ডাবল-কোটেড হয়, যদি এর মধ্যে অক্ষর থাকে যা শেলটির সাথে বিশেষ অর্থযুক্ত থাকে যদি উদ্বুদ্ধ না হয় (যেমন সাদা অংশ)

\Uএবং \Eপ্রতিস্থাপন স্ট্রিং সিকোয়েন্স (যা উপরের ক্ষেত্রে যে প্রতিস্থাপন স্ট্রিং এর অংশ) গনুহ হয় sedএক্সটেনশান। ম্যাকোস এবং বিএসডি-তে আপনি -eএকই প্রভাব অর্জন করতে কেবল একাধিক এক্সপ্রেশন ব্যবহার করবেন ।

বিভাগের নামগুলিতে এম্বেড করা উক্তি এবং শ্বেত স্পেসের সাথে ডিল করা (যা git configমঞ্জুরি দেয়) পাঠকের অনুশীলন হিসাবে ছেড়ে দেওয়া হয়েছে।:)

বাশ এসোসিয়েটিভ অ্যারেতে কী হিসাবে বিভাগের নামগুলি ব্যবহার করা

প্রদত্ত:

; foo.ini
[foobar]
session=foo
path=/some/path

[barfoo]
session=bar
path=/some/path

এটি ওপি সিড প্রতিস্থাপনের এক্সপ্রেশনটিতে কিছু ক্যাপচারকে পুনরায় সাজিয়ে ফলাফলটি জিজ্ঞাসা করবে এবং জিএনইউ সিড ছাড়াই সূক্ষ্মভাবে কাজ করবে:

source <(
    git config -f foo.ini --list \
      | sed 's/\([^.]*\)\.\(.*\)=\(.*\)/declare -A \2["\1"]="\3"/'
)

আমি ভবিষ্যদ্বাণী করি একটি বাস্তব-বিশ্বের .iniফাইলের উদ্ধৃতি দেওয়ার সাথে কিছু চ্যালেঞ্জ থাকতে পারে তবে এটি প্রদত্ত উদাহরণের জন্য কাজ করে। ফলাফল:

declare -p {session,path}
# result:
# declare -A session=([barfoo]="bar" [foobar]="foo" )
# declare -A path=([barfoo]="/some/path" [foobar]="/some/path" )
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.