ফাইল থেকে লোড স্ট্রিংয়ে ভেরিয়েবলগুলি প্রসারিত করতে বাশকে বাধ্য করা হচ্ছে


89

আমি স্ট্রিংয়ে কীভাবে ব্যাশ (ফোর্স?) প্রসারিত ভেরিয়েবলগুলি তৈরি করতে পারি তা চেষ্টা করার চেষ্টা করছি (যা কোনও ফাইল থেকে লোড হয়েছিল)।

আমার কাছে বিষয়বস্তু সহ "काहीतरी. টেক্সট" নামে একটি ফাইল রয়েছে:

hello $FOO world

আমি তখন দৌড়

export FOO=42
echo $(cat something.txt)

এটি ফিরে আসে:

   hello $FOO world

ভেরিয়েবল সেট করা সত্ত্বেও এটি $ এফওও প্রসারিত হয়নি। আমি ফাইলটি উত্সাহিত বা উত্স করতে পারছি না - এটি চেষ্টা করে এটি কার্যকর করে দেবে (এটি যেমন হয় তেমন কার্যকর হয় না - আমি কেবল ভেরিয়েবলের সাথে ইন্টারপোল্টেড স্ট্রিং চাই)।

কোন ধারনা?



আপনি কি মন্তব্যটি নীচের উত্তরের জন্য বলেছিলেন?
মাইকেল নীল

আমি আপনার জন্য মন্তব্য বোঝাতে চাই। একাধিক উত্তর ব্যবহারের প্রস্তাব দেয় evalএবং এর প্রভাব সম্পর্কে সচেতন হওয়া গুরুত্বপূর্ণ।
ডেনিস উইলিয়ামসন

@ ডেনিস উইলিয়ামসন গেটচা - আমি উত্তর দিতে কিছুটা দেরী করছি তবে ভাল পরামর্শ। এবং অবশ্যই মধ্যবর্তী বছরগুলিতে আমাদের কাছে "শেল শক" এর মতো জিনিস রয়েছে তাই আপনার মন্তব্যটি সময়ের পরীক্ষায় দাঁড়িয়েছে! টিপস টুপি
মাইকেল নিল

এটা কি তোমার প্রশ্নের উত্তর? বাশ একটি
চলকটিতে

উত্তর:


115

আমি যা মনে করি তাতে হোঁচট খেয়েছি এই প্রশ্নের উত্তর: envsubstআদেশ the

envsubst < something.txt

যদি এটি আপনার ডিস্ট্রোতে ইতিমধ্যে উপলব্ধ না হয় তবে এটি

জিএনইউ প্যাকেজ gettext

@ রোকালাইট - '\ $' সমস্যার যত্ন নিতে আমি একটি সামান্য মোড়ক স্ক্রিপ্ট লিখেছিলাম।

(বিটিডব্লিউ, এনভাসবস্টের একটি "বৈশিষ্ট্য" রয়েছে, ইনপুটটিতে কেবল কয়েকটি ভেরিয়েবল প্রসারণের জন্য https://unix.stackexchange.com/a/294400/7088 এ ব্যাখ্যা করা হয়েছে , তবে আমি ব্যতিক্রম হই যে পালানো অনেক বেশি সুবিধাজনক।)

এখানে আমার স্ক্রিপ্ট:

#! /bin/bash
      ## -*-Shell-Script-*-
CmdName=${0##*/}
Usage="usage: $CmdName runs envsubst, but allows '\$' to  keep variables from
    being expanded.
  With option   -sl   '\$' keeps the back-slash.
  Default is to replace  '\$' with '$'
"

if [[ $1 = -h ]]  ;then echo -e >&2  "$Usage" ; exit 1 ;fi
if [[ $1 = -sl ]] ;then  sl='\'  ; shift ;fi

sed 's/\\\$/\${EnVsUbDolR}/g' |  EnVsUbDolR=$sl\$  envsubst  "$@"

4
+1 কমান্ডের বিকল্প, উক্তি অপসারণ, যুক্তি প্রক্রিয়াকরণ ইত্যাদি না করার গ্যারান্টিযুক্ত এটিই একমাত্র উত্তর
জোশ কেলি

6
এটি কেবল পুরোপুরি রফতানি করা শেল ওয়ার্সের জন্য (ব্যাশে) কাজ করে। যেমন S = '$ a $ b'; a = সেট; এক্সপোর্ট বি = রফতানি করা; প্রতিধ্বনি $ এস | envsubst; ফলন: "রফতানি"
গাওথে

4
ধন্যবাদ - আমি মনে করি এত বছর পরেও আমার এই উত্তরটি গ্রহণ করা উচিত।
মাইকেল নিলে

4
তবে এটি ডলার চিহ্ন ( $) পলায়নের ব্যবস্থা করে না , উদাহরণস্বরূপ echo '\$USER' | envsubstবর্তমান ব্যবহারকারীর নামটি একটি পূর্ববর্তী ব্যাকগ্রাউন্ড স্ল্যাশ দিয়ে আউটপুট দেবে, না $USER
রকাল্লাইট

4
এটি brew link --force gettext
হোমব্রাবির

25

অনেকগুলি উত্তর ব্যবহার করে evalএবং echoধরণের কাজ করে তবে বিভিন্ন বিষয় যেমন: একাধিক লাইন, শেল মেটা-অক্ষরগুলি পালনের চেষ্টা করা, টেম্প্লেটের অভ্যন্তরে পালানো বাশ দ্বারা প্রসারিত করার উদ্দেশ্যে নয় etc.

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

apply_shell_expansion() {
    declare file="$1"
    declare data=$(< "$file")
    declare delimiter="__apply_shell_expansion_delimiter__"
    declare command="cat <<$delimiter"$'\n'"$data"$'\n'"$delimiter"
    eval "$command"
}

উদাহরণস্বরূপ, আপনি এটির মতো এটি ব্যবহার করতে পারেন parameters.cfgযা সত্যিই একটি শেল স্ক্রিপ্ট যা কেবলমাত্র ভেরিয়েবলগুলি সেট করে এবং একটি template.txtএমন টেম্পলেট যা এই ভেরিয়েবলগুলি ব্যবহার করে:

. parameters.cfg
printf "%s\n" "$(apply_shell_expansion template.txt)" > result.txt

অনুশীলনে, আমি এটিকে এক ধরণের লাইটওয়েট টেম্পলেট সিস্টেম হিসাবে ব্যবহার করি।


4
এটি আমি এখনও অবধি খুঁজে পাওয়া সেরা কৌশলগুলির মধ্যে একটি :)। আপনার উত্তরের ভিত্তিতে এমন একটি ফাংশন তৈরি করা এত সহজ যা অন্য ভেরিয়েবলের রেফারেন্স যুক্ত স্ট্রিং সহ একটি ভেরিয়েবল প্রসারিত করে - আপনার ফাংশনে কেবলমাত্র $ 1 এর সাথে $ ডেটা প্রতিস্থাপন করুন এবং আমরা এখানে যাই! আমি বিশ্বাস করি এটিই মূল প্রশ্নের সেরা উত্তর, বিটিডাব্লু।
গ্যালাক্সি

এমনকি এটির স্বাভাবিক evalসমস্যাও রয়েছে। ; $(eval date)ইনপুট ফাইলের অভ্যন্তরে যে কোনও লাইনের শেষে যুক্ত করার চেষ্টা করুন এবং এটি dateকমান্ডটি চালাবে ।
অনুভা

4
@ অনুভা আমি আপনার অর্থ কী তা নিশ্চিত নই; এটাই আসলে এই ক্ষেত্রে কাঙ্ক্ষিত সম্প্রসারণ আচরণ। অন্য কথায়, হ্যাঁ, আপনি এটি দিয়ে স্বেচ্ছাসেবী শেল কোডটি কার্যকর করতে সক্ষম হবেন বলে মনে করা হচ্ছে।
wjl

22

আপনি চেষ্টা করতে পারেন

echo $(eval echo $(cat something.txt))

9
আপনার echo -e "$(eval "echo -e \"`<something.txt`\"")"যদি নতুন লাইন রাখার দরকার হয় তবে ব্যবহার করুন ।
পেভিক


4
তবে কেবল যদি আপনার template.txtপাঠ্য হয়। এই অপারেশনটি বিপজ্জনক কারণ এটি যদি হয় তবে আদেশগুলি কার্যকর করে (ওভালিউটস)।
kyb

4
তবে এটি ডাবল-উক্তিটি সরিয়ে
ফেলল

সাবসেলের উপর দোষ দিন।
ingehere

8

আপনি প্রতিটি লাইন মুদ্রণ করতে চান না, আপনি এটির মূল্যায়ন করতে চান যাতে বাশ পরিবর্তনশীল বিকল্পগুলি সম্পাদন করতে পারে।

FOO=42
while read; do
    eval echo "$REPLY"
done < something.txt

help evalআরও তথ্যের জন্য বাশ ম্যানুয়ালটি দেখুন বা দেখুন ।


4
evalবিপজ্জনক ; আপনি কেবল $varnameপ্রসারিত হবেন না (যেমনটি আপনি দিয়েছিলেন envsubst) তবে $(rm -rf ~)পাশাপাশি।
চার্লস ডাফি

4

আরেকটি পদ্ধতির (যা দেখতে চটকদার বলে মনে হচ্ছে, তবে আমি এটি এখানে রাখছি):

কোনও টেম্পল ফাইলটিতে টেক্সট ফাইলের লিখিত সামগ্রী লিখুন, যার চারপাশে প্রতিধ্বনি আবদ্ধ থাকে:

something=$(cat something.txt)

echo "echo \"" > temp.out
echo "$something" >> temp.out
echo "\"" >> temp.out

তারপরে এটিকে আবার চলকটিতে উত্স দিন:

RESULT=$(source temp.out)

এবং ES ফলস্বরূপ এটি সমস্ত প্রসারিত হবে। তবে এতো ভুল মনে হচ্ছে!


4
আইকি তবে এটি সবচেয়ে সোজা-এগিয়ে, সহজ এবং কাজ করে।
kyb

3

আপনি যদি কেবলমাত্র পরিবর্তনশীল উল্লেখগুলি প্রসারিত করতে চান (একটি উদ্দেশ্য যা আমার নিজের জন্য ছিল) আপনি নীচেরটি করতে পারেন।

contents="$(cat something.txt)"
echo $(eval echo \"$contents\")

(পালানো উদ্ধৃতিগুলি প্রায় $ বিষয়বস্তু এখানে মূল)


আমি এটি চেষ্টা করেছি, তবে $ () আমার ক্ষেত্রে লাইন শেষগুলি সরিয়ে দেয় যা ফলস্বরূপ স্ট্রিংটি ভেঙে দেয়
moz

আমি ইভাল লাইনটি এতে পরিবর্তন করেছি eval "echo \"$$contents\""এবং এটি সাদা স্থান সংরক্ষণ করেছে
মোজ

2
  1. প্রক্রিয়াকমান্ডের বিকল্প ব্যবহার করে যদি কোন কিছু টেক্সটে কেবল একটি লাইন থাকে, একটি bashপদ্ধতি থাকে ( মাইকেল নেলের "আইকি" উত্তরটির একটি সংক্ষিপ্ত সংস্করণ ) থাকে :

    FOO=42 . <(echo -e echo $(<something.txt))
    

    আউটপুট:

    hello 42 world
    

    নোট করুন যে exportপ্রয়োজন হয় না।

  2. যদি কোন কিছু টেক্সটে এক বা একাধিক লাইন থাকে তবে একটি জিএনইউ মূল্যবান পদ্ধতি:sed e

    FOO=42 sed 's/"/\\\"/g;s/.*/echo "&"/e' something.txt
    

4
আমি sedআমার উদ্দেশ্যটি সবচেয়ে উপযুক্ত করতে মূল্যায়নটি খুঁজে পেয়েছি । আমার টেমপ্লেটগুলি থেকে স্ক্রিপ্টগুলি উত্পাদন করা দরকার, যার অন্য ভেরিয়েবলের মধ্যে অন্য ভেরিয়েবলের মধ্যে রফতানি করা ভেরিয়েবলগুলি থেকে ভ্যালু ভরা হত। এটি কমান্ড প্রসারণ যেমন আউটপুট \$(date)পেতে টেমপ্লেটে রাখার জন্য যথাযথভাবে পালিয়ে যাওয়া পরিচালনা $(date)করে। ধন্যবাদ!
গাদামিয়াক

1

নিম্নলিখিত সমাধান:

  • সংজ্ঞাযুক্ত ভেরিয়েবলগুলি প্রতিস্থাপনের অনুমতি দেয়

  • সংশোধিত নয় এমন অপরিবর্তিত ভেরিয়েবল স্থানধারককে ছেড়ে দেয়। এটি স্বয়ংক্রিয় মোতায়েনের সময় বিশেষত কার্যকর।

  • নিম্নলিখিত ফর্ম্যাটগুলিতে ভেরিয়েবল প্রতিস্থাপন সমর্থন করে:

    ${var_NAME}

    $var_NAME

  • প্রতিবেদনগুলি যা ভেরিয়েবলগুলি পরিবেশে সংজ্ঞায়িত করা হয় না এবং এই জাতীয় ক্ষেত্রে ত্রুটি কোড দেয়



    TARGET_FILE=someFile.txt;
    ERR_CNT=0;

    for VARNAME in $(grep -P -o -e '\$[\{]?(\w+)*[\}]?' ${TARGET_FILE} | sort -u); do     
      VAR_VALUE=${!VARNAME};
      VARNAME2=$(echo $VARNAME| sed -e 's|^\${||g' -e 's|}$||g' -e 's|^\$||g' );
      VAR_VALUE2=${!VARNAME2};

      if [ "xxx" = "xxx$VAR_VALUE2" ]; then
         echo "$VARNAME is undefined ";
         ERR_CNT=$((ERR_CNT+1));
      else
         echo "replacing $VARNAME with $VAR_VALUE2" ;
         sed -i "s|$VARNAME|$VAR_VALUE2|g" ${TARGET_FILE}; 
      fi      
    done

    if [ ${ERR_CNT} -gt 0 ]; then
        echo "Found $ERR_CNT undefined environment variables";
        exit 1 
    fi


0
foo=45
file=something.txt       # in a file is written: Hello $foo world!
eval echo $(cat $file)

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

-1

envsubst আপনি যে বিষয়বস্তুটি প্রতিস্থাপন করছেন সেটি যদি "যুক্তিসঙ্গত" দৈর্ঘ্যের হয় তবে এটি একটি দুর্দান্ত সমাধান (লেনডাব্লুয়ের উত্তর দেখুন)।

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

অজানা সমাধান

ভিন্ন প্রশ্ন থেকে কিউংলমের সমাধানটি ব্যবহার করা :

needle="doc1_base64" # The "variable name" in the file. (A $ is not needed.)
needle_file="doc1_base64.txt" # Will be substituted for the needle 
haystack=$requestfile1 # File containing the needle
out=$requestfile2
awk "BEGIN{getline l < \"${needle_file}\"}/${needle}/{gsub(\"${needle}\",l)}1" $haystack > $out

এই সমাধান এমনকি বড় ফাইলের জন্যও কাজ করে।


-3

নিম্নলিখিত কাজ করে: bash -c "echo \"$(cat something.txt)"\"


এটি কেবল অদক্ষ নয়, এটি অত্যন্ত বিপজ্জনক; এটি কেবল নিরাপদ সম্প্রসারণের মতো চালায় না $foo, তবে অনিরাপদ পছন্দ করে $(rm -rf ~)
চার্লস ডাফি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.