পাইপে স্ক্রিপ্ট ব্যবহার করার সময় ব্যবহারকারী ইনপুট কীভাবে পড়বেন read


10

সাধারণ সমস্যা

আমি এমন একটি স্ক্রিপ্ট লিখতে চাই যা পাইপের শৃঙ্খলের মাঝে থাকা সত্ত্বেও এটির সাথে ইন্টারেক্ট করে।

কংক্রিট উদাহরণ

কংক্রিটলি, এটি একটি fileবা stdin, লাইনগুলি প্রদর্শন করে (লাইন সংখ্যা সহ), ব্যবহারকারীকে একটি নির্বাচন বা লাইন সংখ্যা ইনপুট করতে বলে এবং তারপরে সংশ্লিষ্ট লাইনগুলি মুদ্রণ করে stdout। এই স্ক্রিপ্ট কল করুন selector। তারপর মূলত, আমি করতে সক্ষম হতে চাই

grep abc foo | selector > myfile.tmp

যদি fooথাকে

blabcbla
foo abc bar
quux
xyzzy abc

তারপরে অপশন সহ selectorআমাকে উপস্থাপন করুন (টার্মিনালে, না myfile.tmp!)

1) blabcbla
2) foo abc bar
3) xyzzy abc
Select options:

যার পরে আমি টাইপ করি

2-3

এবং শেষ পর্যন্ত

foo abc bar
xyzzy abc

বিষয়বস্তু হিসাবে myfile.tmp

আমি একটি নির্বাচক স্ক্রিপ্ট পেয়েছি এবং চলমান আছে, এবং মূলত এটি পুরোপুরি কাজ করছে যদি আমি ইনপুট এবং আউটপুটটিকে পুনর্নির্দেশ না করি। সুতরাং

selector foo

আমি চাই যেমন আচরণ। তবে উপরের উদাহরণের মতো জিনিসগুলি একসাথে পাইপ করার সময় selectorউপস্থাপিত বিকল্পগুলি মুদ্রণ করে myfile.tmpএবং গ্রেপড ইনপুট থেকে একটি নির্বাচন পড়ার চেষ্টা করে।

আমার পদ্ধতির

আমি এর -uপতাকা readহিসাবে ব্যবহার করার চেষ্টা করেছি

exec 4< /proc/$PPID/fd/0
exec 4> /proc/$PPID/fd/1
nl $INPUT >4
read -u4 -p"Select options: "

তবে এটি আমি যা আশা করি তা করে না।

প্রশ্ন: আমি কীভাবে প্রকৃত ব্যবহারকারীর ইন্টারঅ্যাকশন পেতে পারি?


স্ক্রিপ্ট তৈরি করুন এবং আউটপুটটিকে ভেরিয়েবলে সংরক্ষণ করুন, এবং তারপরে উপস্থিত ব্যবহারকারী আপনার চান চান ??
হ্যাকাহলিক

@ হ্যাকাহোলিক - আপনার অর্থ কী তা আমি নিশ্চিত নই। আমি এমন একটি স্ক্রিপ্ট চাই যা কোনও ধরণের পাইপলাইন সিকোয়েন্সে (যেমন ইউনিক্স উপায়ে) স্থাপন করা যেতে পারে। আমি উপরে একটি বিস্তৃত উদাহরণ দিয়েছি, তবে এটি অবশ্যই আমার মনে একমাত্র ব্যবহারের ঘটনা নয়।
জেএমসি

1
ব্যবহার করুনcmd | { some processing; read var </dev/tty; } | cmd
মাইক্রজারভ

@ মিমকিজার - আকর্ষণীয়! আমার এখন alias selector='{ TMPFILE=$(mktemp); cat > $TMPFILE; nl -s") " $TMPFILE | column -c $(tput cols); read -e -p"Select options: " < /dev/tty; rangeselect -v range="$REPLY" $TMPFILE; rm $TMPFILE; }'যা খুব ভাল কাজ করে। তবে grep b foo | selector | wc -lএখানে বিরতি। কোনও ধারণা কীভাবে এটি ঠিক করবেন? যাইহোক, rangeselectআমি যেটি ব্যবহার করেছি তা পেস্টবিন . com/ভিএক্সটিএসএসএইচে পাওয়া যাবে । এটি একটি সরল এডাব্লুকে স্ক্রিপ্ট যা লাইনেনারের একটি নির্দিষ্ট পরিসীমা সম্পর্কিত কোনও ফাইলের লাইনগুলি মুদ্রণ করে। (পরিসীমাগুলি "3-10, 12,14,16-20-20" এর মতো জিনিস হতে পারে))
জেএমসি

1
না aliasবরং যে selector() { all of that stuff...; }একটি ফাংশন মধ্যে। aliasস্প্যানিশ ভাষায় নামান্তর সহজ কমান্ড যেহেতু ফাংশন একটি প্যাক যৌগ কমান্ড একটি একক মধ্যে সহজ কমান্ড
মাইকজার্ভ

উত্তর:


8

ব্যবহার /proc/$PPID/fd/0অবিশ্বাস্য: selectorপ্রক্রিয়াটির পিতামাতার এর ইনপুট হিসাবে টার্মিনাল নাও থাকতে পারে।

একটা হল মান পথ যে সবসময় বর্তমান প্রক্রিয়া এর টার্মিনাল বোঝায়: /dev/tty

nl "$INPUT" >/dev/tty
read -p"Select options: " </dev/tty

অথবা

exec </dev/tty >/dev/tty
nl "$INPUT"
read -p"Select options: "

1
ধন্যবাদ, এটি আমার সমস্যার সমাধান করে। উত্তরটি যদিও কিছুটা স্বল্পতর। আমার ধারণা, প্রশ্নের মন্তব্যে মাইক্রজারের কিছু পরামর্শ অন্তর্ভুক্ত করে এটি উপকৃত হতে পারে।
জেএমসি

2

আমি একটি ছোট ফাংশন লিখেছি: এটি আপনি পাইপের শৃঙ্খলা যা জিজ্ঞাসা করেছেন সে সম্পর্কে উত্তর দেবে না তবে এটি আপনার সমস্যার সমাধান করবে।

inf() ( [ -n "$ZSH_VERSION" ] && emulate sh
        unset n i c; set -f; tab='      ' IFS='
';      _in()   until [ "$((i+=1))" -gt 5 ] && exit 1
                printf '\nSelect: '
                read -r c && [ -n "${c##*[!- 0-9]*}" ]
                do echo "Invalid selection."
                done
        _out()  for n do i=; [ "$n" = . ]  &&
                printf '"${%d#*$tab}" ' $c ||
                until c="${c#*.} ${i:=${n%%-*}}"
                [ "$((i+=1))" -gt "${n#*-}" ]
                do :; done; done
set -- $(grep "$@"|nl -w1 -s "$tab"|tee /dev/tty)
i=$((($#<1)*5)); _in </dev/tty >/dev/tty
eval "printf '%s\n' $(c=$c\ . IFS=\ ;_out $c)"
)

ফাংশনটি আপনাকে তা তাত্ক্ষণিকভাবে প্রদান করে এমন সমস্ত আর্গুমেন্টকে ঘুরিয়ে দেয় grep। আপনি যদি শেল গ্লোব ব্যবহার করেন তবে এটি পড়তে হবে এমন ফাইলগুলি নির্দিষ্ট করতে সমস্ত ফাইলের সমস্ত ম্যাচ গ্লোব ক্রমে শুরু করে এবং শেষ ম্যাচ দিয়ে শেষ হবে return

grepnlপ্রতিটি লাইনকে কোন সংখ্যায় সংখ্যায় আউটপুটটি পাস করে এবং যা তার আউটপুটটি পাস করে teeযা তার আউটপুটকে stdoutএবং উভয়ই প্রতিলিপি করে /dev/tty। এর অর্থ পাইপলাইন থেকে আউটপুট একই সাথে ফাংশনটির আর্গুমেন্ট অ্যারে উভয় মুদ্রিত হয় যেখানে এটি \nইওলাইনগুলিতে বিভক্ত হয় এবং টার্মিনাল যেমন এটি কাজ করে ততক্ষণে।

পরবর্তী _in()ক্রিয়াটি readএকটি নির্বাচনের চেষ্টা করে যদি পূর্ববর্তী ক্রিয়া থেকে সর্বাধিক পাঁচবারের জন্য কমপক্ষে 1 ফলাফল হয়। নির্বাচনটি ফাঁকা দ্বারা বিভাজিত কেবলমাত্র সংখ্যার সমন্বয়ে গঠিত হতে পারে, না হলে সংখ্যা রেঞ্জগুলি দ্বারা পৃথক -। অন্য কিছু যদি read (ফাঁকা লাইন সহ) থাকে তবে এটি আবার চেষ্টা করবে - তবে কেবল আগের মতো সর্বাধিক পাঁচবার।

সর্বশেষে _out()ফাংশনটি ব্যবহারকারীর নির্বাচনের বিশ্লেষণ করে এবং এতে কোনও ব্যাপ্তি প্রসারিত করে। এটি "${[num]}"প্রত্যেকের জন্য ফর্মটিতে তার ফলাফলগুলি মুদ্রণ করে - এর ফলে inf()আরগ অ্যারেতে সঞ্চিত রেখার মানটির সাথে মিলে যায় । এই আউটপুটটি evalআরোগুলি হিসাবে সম্পাদনা করা হয়েছে printfযার ফলে ব্যবহারকারীরা কেবল নির্বাচিত রেখাগুলি মুদ্রণ করে।

এটি স্পষ্টভাবে readটার্মিনাল থেকে এসেছে এবং কেবল Select:মেনুতে মুদ্রণ করে stderrএবং তাই এটি যথেষ্ট পরিমাণে পাইপলাইন বান্ধব। উদাহরণস্বরূপ, নিম্নলিখিত কাজগুলি:

seq 100 |inf 3|grep 8
1       3
2       13
3       23
4       30
5       31
6       32
7       33
8       34
9       35
10      36
11      37
12      38
13      39
14      43
15      53
16      63
17      73
18      83
19      93

Select: 6 9 12-18
38
83

তবে আপনি যে কোনও বিকল্প দিতে পারবেন grepএবং যে কোনও ফাইল নামও আপনি এটিকে হ্যান্ড করতে পারেন। এটি হ'ল, আপনি এক প্রকার ব্যতীত অন্য কোনওটি ব্যবহার করতে পারেন - এর পার্সিং ইনপুটটির পার্শ্ব-প্রতিক্রিয়া হিসাবে $IFSএটি খালি রেখাগুলি সন্ধান করা থাকলে কাজ করবে না। কিন্তু খালি রেখার একটি সংখ্যাযুক্ত তালিকা থেকে কে নির্বাচন করতে চান?

সর্বশেষ নোটটি যেহেতু এটি ফাংশনটির আর্গুমেন্ট অ্যারেতে সঞ্চিত সংখ্যাগত অবস্থানগত পরামিতিগুলিতে সংখ্যার ব্যবহারকারী ইনপুটটিকে সরাসরি অনুবাদ করে কাজ করে, তারপরে ব্যবহারকারী যতবার নির্বাচন করে, আউটপুট ব্যবহারকারী তার যতবার নির্বাচন করে, এবং যেকোন আদেশে ব্যবহারকারী নির্বাচন করে এটা।

উদাহরণ স্বরূপ:

seq 1000 | inf 00\$

1       100
2       200
3       300
4       400
5       500
6       600
7       700
8       800
9       900
10      1000

Select: 4-8 1 1 3-6
400
500
600
700
800
100
100
300
400
500
600

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

@ মেকজার্ হ্যাঁ আপনি ঠিক বলেছেন, আমি অনুপযুক্ত ইনপুট এবং সমস্ত কিছুর মতো সমস্ত জিনিসই বৈধতা দিয়েছি না। আপনার বক্তব্যের জন্য ধন্যবাদ
হ্যাকাহলিক

@ মিকসার্ভ আমি শেল প্রোগ্রামিংয়ের সমস্ত বেসিক জানি, আপনি কীভাবে আমাকে উন্নত হতে পারেন তা গাইড করতে পারেন
হ্যাকাহলিক

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