bash এ স্ট্রাক্ট করে কমান্ড বিল্ড করুন


13

আমার কাছে বাশ স্ক্রিপ্ট রয়েছে যা একবারে চালুর আগে কিছু পরামিতিগুলির উপর ভিত্তি করে স্ট্রিংয়ে কমান্ড-লাইন তৈরি করে। কমান্ড স্ট্রিংয়ের সাথে সংযুক্ত হওয়া যে অংশগুলি প্রতিটি উপাদানগুলির মাধ্যমে ডেটার একটি "স্ট্রিমিং" করার সুবিধার্থে পাইপগুলি দ্বারা পৃথক করা উচিত।

খুব সরল উদাহরণ:

#!/bin/bash
part1=gzip -c
part2=some_other_command
cmd="cat infile"

if [ ! "$part1" = "" ]
then
    cmd+=" | $part1"
fi


if [ ! "$part2" = "" ]
then
    cmd+=" | $part2"
fi


cmd+="> outfile"
#show command. It looks ok
echo $cmd
#run the command. fails with pipes
$cmd

কিছু কারণে পাইপগুলি কাজ করছে বলে মনে হয় না। আমি যখন এই স্ক্রিপ্টটি চালনা করি তখন কমান্ডের প্রথম অংশের সাথে সম্পর্কিত প্রথম ত্রুটির বার্তা পাই (প্রথম পাইপের আগে)।

সুতরাং আমার প্রশ্নটি এইভাবে কোনও কমান্ড তৈরি করা সম্ভব কিনা এবং এটি করার সর্বোত্তম উপায় কী?


ত্রুটি বার্তা কি?
ক্যামেরননো

আমার স্ক্রিপ্টে (যা এই সরলকরণের চেয়ে কিছুটা জটিল) আমি "ফাইল খুঁজে পাইনি"
লেনার্ট রোলল্যান্ড

infileবর্তমান ডিরেক্টরিতে এটি বিদ্যমান তা অনুমান করা কি নিরাপদ ?
saiarcot895

হ্যাঁ. আমার কোডে এটি একটি ফাইলের পরিবর্তে - উইজেট -O। আসলে, যদি আমি কেবল সংক্ষিপ্ত স্ট্রিংটি অনুলিপি করি এবং টার্মিনালে এটি প্যাসেট করি তবে এটি ঠিক আছে
লেনার্ট

উত্তর:


17

বিষয়গুলি কখন মূল্যায়ন করা হয় তার উপর নির্ভর করে। আপনি যখন টাইপ করেন $cmd, তখন পুরো বাকী রেখাটি প্রথম শব্দের সাথে যুক্তি হিসাবে পাস করা হয় $cmd

walt@spong:~(0)$ a="cat /etc/passwd"
walt@spong:~(0)$ b="| wc -l"
walt@spong:~(0)$ c="$a $b"
walt@spong:~(0)$ echo $c
cat /etc/passwd | wc -l
walt@spong:~(0)$ $c
cat: invalid option -- 'l'
Try 'cat --help' for more information.
walt@spong:~(1)$ eval $c
62
walt@spong:~(0)$ a="echo /etc/passwd"
walt@spong:~(0)$ c="$a $b"
walt@spong:~(0)$ echo $c
echo /etc/passwd | wc -l
walt@spong:~(0)$ $c
/etc/passwd | wc -l
walt@spong:~(0)$ $c |od -bc
0000000 057 145 164 143 057 160 141 163 163 167 144 040 174 040 167 143  
          /   e   t   c   /   p   a   s   s   w   d       |       w   c  
0000020 040 055 154 012  
              -   l  \n  
0000024
walt@spong:~(0)$ eval $c
1  

এটি দেখায় যে echoকমান্ডে আর্গুমেন্টগুলি হ'ল : " /etc/passwd", " |" (উল্লম্ব বারের অক্ষর), " wc" এবং " -l"।

থেকে man bash:

eval [arg ...]  
    The  args  are read and concatenated together into   
    a single command.  This command is then read and  
    executed by the shell, and its exit status is returned  
    as the value of eval.  If there are no args, or only null  
    arguments, eval returns 0.

8

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

সুতরাং উপরের উদাহরণে, প্রতিস্থাপন

$cmd

সঙ্গে

eval $cmd

এটি সমাধান করুন।


উদ্ধৃত পরামিতি সহ সতর্কতা অবলম্বন করুন। eval foo "a b"হিসাবে একই হবে eval foo "a" "b"
উদোনডান

2

@ ওয়াল্টিনেটর ইতিমধ্যে ব্যাখ্যা করেছে যে এটি আপনার প্রত্যাশার মতো কেন কাজ করে না। এর চারপাশের অন্য উপায়টি হ'ল bash -cআপনার আদেশটি কার্যকর করতে:

$ comm="cat /etc/passwd"
$ comm+="| wc -l"
$ $comm
cat: invalid option -- 'l'
Try 'cat --help' for more information.
$ bash -c "$comm"
51

1
পার্সিমনি আমাকে অন্য প্রক্রিয়া শুরু না করার জন্য বলেছে bash -c, তবে evalবর্তমান প্রক্রিয়াতে কমান্ডটি ব্যবহার করতে ব্যবহার করুন ।
ওয়ালটিনেটর

@ ওয়ালটিনেটর নিশ্চিত, আমি সম্ভবত এটির জন্যও ওয়াল ব্যবহার করব (যার কারণে আমি আপনাকে এবং লেনার্টকে উজ্জীবিত করেছি)। আমি কেবল একটি বিকল্প সরবরাহ করছি।
টেরডন

0

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

runcmd=() # This is slightly messier than declare -a but works
for cmd in $part1 $part2 $part3; do runcmd+="| $cmd "; done
cat infile ${runcmd[@]} # You might be able to do $basecmd ${runcmd[@]}
# but that sometimes requires an `eval` which isn't great
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.