আমার শেল স্ক্রিপ্টটি কোনও পাইপের মধ্য দিয়ে চলছে কিনা তা কীভাবে সনাক্ত করবেন?


252

শেল স্ক্রিপ্টের মধ্যে থেকে কীভাবে সনাক্ত করব যদি এর স্ট্যান্ডার্ড আউটপুটটি টার্মিনালে প্রেরণ করা হয় বা এটি অন্য কোনও প্রক্রিয়াতে পাইপ করা হয়?

ঘটনাটির ক্ষেত্রে: আমি আউটপুট রঙিন করতে এস্কেপ কোড যুক্ত করতে চাই, তবে কেবল ইন্টারেক্টিভভাবে চালিত হলে, যখন পাইপ করা হয় না তখন যা ls --colorহয় তার অনুরূপ ।


2
এখানে আরও কিছু আকর্ষণীয় পরীক্ষার মামলা রয়েছে! <a href=" serverfault.com/questions/156470/… স্ক্রিপ্টের জন্য অপেক্ষা করা হচ্ছে যে স্টিডিনে অপেক্ষা করছে </a>

2
@ user940324 সঠিক লিঙ্ক serverfault.com/q/156470/197218
Palec

উত্তর:


385

খাঁটি POSIX শেলের মধ্যে,

if [ -t 1 ] ; then echo terminal; else echo "not a terminal"; fi

"টার্মিনাল" প্রদান করে, কারণ আউটপুটটি আপনার টার্মিনালে প্রেরণ করা হয় whereas

(if [ -t 1 ] ; then echo terminal; else echo "not a terminal"; fi) | cat

"টার্মিনাল নয়" প্রদান করে, কারণ প্যারেন্টিকের আউটপুটটি পাইপ করা হয় cat


-tপতাকা মানুষ পাতায় বর্ণনা করা হয়েছে

-t fd সত্য যদি ফাইল বর্ণনাকারী fd খোলা থাকে এবং একটি টার্মিনাল বোঝায়।

... যেখানে fdসাধারণ ফাইল বর্ণনাকারী কার্যভারগুলির মধ্যে একটি হতে পারে:

0:     stdin  
1:     stdout  
2:     stderr

1
@ ক্যালভিন সেখানে ম্যান পেজ স্নিপেট পরামর্শ দেয় যে এটি করা উচিত, কিন্তু সেই ফাইল বিবরণকারীদের ডিফল্টরূপে বরাদ্দ করা হয় না।
ডিএমকেকে --- প্রাক্তন-মডারেটর বিড়ালছানা

41
স্পষ্ট করার জন্য, -tপতাকাটি পসিক্সে নির্দিষ্ট করা হয়েছে এবং সুতরাং কোনও পসিক্স-সামঞ্জস্যপূর্ণ শেলের জন্য এটি কাজ করা উচিত (এটি কোনও বাশ এক্সটেনশন নয়)। pubs.opengroup.org/onlinepubs/009695399/utilities/test.html
জোনাকি না

Ssh দূরবর্তী কমান্ড হিসাবে স্ক্রিপ্ট চালানোর সময় কাজ করে। সর্বকালের সেরা উত্তর এবং খুব সহজ।
লিনাক্স_নিউবি

আমি সম্মত হই যে আপনার সম্পাদনার পরে (পুনর্বিবেচনা 5), উত্তরটি 3 সংশোধনীর তুলনায় আরও স্পষ্ট এবং সত্যই সঠিক (উপেক্ষা করে "রিটার্ন" খুব অনানুষ্ঠানিকভাবে ব্যবহৃত হয় যেখানে "প্রিন্ট" আরও সুনির্দিষ্ট হবে)।
প্যালেক

fishশেলের উত্তর খুঁজছিল । ব্যবহার testকরা ঝরঝরে, তবে আমি সমর্থিত উদাহরণটি চেষ্টা করতে পারি না কারণ এটি সমর্থিত নয়। এটি সাদৃশ্যযুক্ত করে মোড়ানোর চেষ্টা করা হয়েছে begin; ...; end, তবে এটি কাজ করে বলে মনে হচ্ছে না এবং কেবল ইতিবাচক কোড ব্লকটি চালিয়েছে। ভেবেছিলাম আমার ব্যবহারের প্রয়োজন হতে পারে statusতবে এটি পাইপিংয়ের জন্য যাচাই করে নি। আমি অনুমান করি যে আমি পূর্ববর্তী কমান্ড / স্ক্রিপ্টের STDOUT টার্মিনালে সেট করা নেই কিনা তা অবশ্যই জানতে চাই, এই পরিষ্কার উত্তরগুলির জন্য ধন্যবাদ।
পাইসিস

126

আপনার স্ক্রিপ্টে / থেকে STDIN, STDOUT বা STDERR পাইপ করা হচ্ছে কিনা তা নির্ধারণ করার কোনও বুদ্ধিমান উপায় নেই , মূলত প্রোগ্রামগুলির কারণে ssh

যে জিনিসগুলি "সাধারণত" কাজ করে

উদাহরণস্বরূপ, নিম্নলিখিত ব্যাশ সমাধানটি একটি ইন্টারেক্টিভ শেলটিতে সঠিকভাবে কাজ করে:

[[ -t 1 ]] && \
    echo 'STDOUT is attached to TTY'

[[ -p /dev/stdout ]] && \
    echo 'STDOUT is attached to a pipe'

[[ ! -t 1 && ! -p /dev/stdout ]] && \
    echo 'STDOUT is attached to a redirection'

তবে তারা সবসময় কাজ করে না

যাইহোক, এই কমান্ডটি একটি নন-টিটিওয়াই কমান্ড হিসাবে চালিত করার সময় ssh, এসটিডি স্ট্রিমগুলি সর্বদা দেখে মনে হয় যে সেগুলি পাইপ করা হচ্ছে। এটি প্রদর্শনের জন্য, STDIN ব্যবহার করা সহজ কারণ এটি সহজ:

# CORRECT: Forced-tty mode correctly reports '1', which represents
# no pipe.
ssh -t localhost '[[ -p /dev/stdin ]]; echo ${?}'

# CORRECT: Issuing a piped command in forced-tty mode correctly
# reports '0', which represents a pipe.
ssh -t localhost 'echo hi | [[ -p /dev/stdin ]]; echo ${?}'

# INCORRECT: Non-tty mode reports '0', which represents a pipe,
# even though one isn't specified here.
ssh -T localhost '[[ -p /dev/stdin ]]; echo ${?}'

কেন এটি গুরুত্বপূর্ণ

এটি একটি দুর্দান্ত ব্যাপার, কারণ এর দ্বারা বোঝা যায় যে কোনও নন-টিটি-টি sshকমান্ড পাইপ হচ্ছে কি না তা বলার জন্য বাশ স্ক্রিপ্টের কোনও উপায় নেই । নোট করুন যে এই দুর্ভাগ্যজনক আচরণটি চালু হয়েছিল যখন সাম্প্রতিক সংস্করণগুলি টি ssh-টিওয়াই স্টাডিওর জন্য পাইপ ব্যবহার শুরু করে। পূর্ববর্তী সংস্করণগুলি সকেট ব্যবহার করেছে, যা ব্যবহারের মাধ্যমে বাশের মধ্যে পৃথক হতে পারে [[ -S ]]

যখন এটি গুরুত্বপূর্ণ

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

ssh -t localhost 'echo piped | cat - <( echo substituted )'
ssh -T localhost 'echo piped | cat - <( echo substituted )'

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

অন্যান্য জিনিস যা কাজ করে না

এই সমস্যাটি সমাধান করার চেষ্টা করার সময়, আমি কয়েকটি কৌশল অবলম্বন করেছি যা সমস্যার সমাধান করতে ব্যর্থ হয়েছে যার মধ্যে রয়েছে:

  • এসএসএইচ এনভায়রনমেন্ট ভেরিয়েবল পরীক্ষা করা
  • stat/ dev / stdin ফাইল বর্ণনাকারী ব্যবহার করে
  • মাধ্যমে ইন্টারেক্টিভ মোড পরীক্ষা করা [[ "${-}" =~ 'i' ]]
  • ttyএবং মাধ্যমে tty স্থিতি পরীক্ষা করাtty -s
  • sshমাধ্যমে স্থিতি পরীক্ষা করা[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]

মনে রাখবেন যে আপনি যদি /procভার্চুয়াল ফাইল সিস্টেমটিকে সমর্থন করে এমন কোনও ওএস ব্যবহার করছেন, তবে কোনও পাইপ ব্যবহৃত হচ্ছে কিনা তা নির্ধারণের জন্য আপনার স্টাডিওয়ের প্রতীকী লিঙ্কগুলি অনুসরণ করার ভাগ্য থাকতে পারে। তবে, /procকোনও ক্রস প্ল্যাটফর্ম নয়, পসিক্স-সামঞ্জস্যপূর্ণ সমাধান।

আমি এই সমস্যাটি সমাধানে অত্যন্ত আকর্ষণীয়, সুতরাং দয়া করে আপনি যদি অন্য কোনও প্রযুক্তি সম্পর্কে কাজ করে যা সম্ভবত পিনাক্স-ভিত্তিক সমাধান যা লিনাক্স এবং বিএসডি উভয় ক্ষেত্রেই কাজ করে সে সম্পর্কে মনে করেন তবে আমাকে জানান know


2
পরিবেশের পরিবর্তনশীল বা প্রক্রিয়াগুলির নামগুলি পরিষ্কারভাবে পরিদর্শন করা খুব বিশ্বাসযোগ্য নয় ur তবে আপনি কি কিছুটা প্রসারিত করতে পারেন কেন অন্যান্য হিরিস্টিক্স এই উদ্দেশ্যে অযোগ্য বা তাদের সমস্যাটি কী? উদাহরণস্বরূপ আমি stat/ ডিভ / স্টিডিনে কোনও কল আউটপুটে কোনও পার্থক্য দেখতে পাচ্ছি না । কি কারনে চাইছি "${-}"বা tty -sকাজ করে না? আমি এর উত্স catকোডটিও দেখেছি তবে কোন অংশটি সেখানে যাদু করছে তা দেখতে ব্যর্থ হয়েছি যা আপনি পসিক্স শেলটিতে করতে পারবেন না। আপনি যে প্রসারিত করতে পারে?
josch

30

কমান্ডটিতে test(অন্তর্নির্মিত bash) কোনও ফাইল বর্ণনাকারী টিটিটি কিনা তা পরীক্ষা করার বিকল্প রয়েছে।

if [ -t 1 ]; then
    # stdout is a tty
fi

দেখুন " man test" বা " man bash" এবং "এর জন্য অনুসন্ধান -t"


3
"ম্যান টেস্ট" এর জন্য +1 কারণ / ইউএসআর / বিন / পরীক্ষা এমনকি এমন একটি শাঁটেও কাজ করবে যা এর বিল্ট-ইন টেস্টে প্রয়োগ করে না
নীল মেহেজ

4
ডেমকির উত্তরে ফায়ারফ্লাই দ্বারা উল্লিখিত হিসাবে, একটি শেল যা-টি প্রয়োগ করে না - পসিক্সের সাথে খাপ খায় না।
scy

আরও গভীর-তথ্যের জন্য বাশের বিল্টিন help test(এবং help helpআরও কিছু) info bashদেখুন। আপনি যদি কখনও অফলাইনে স্ক্রিপ্টিং শেষ করেন বা কেবল আরও বিস্তৃত বোঝার জন্য চান তবে এই আদেশগুলি দুর্দান্ত।
জোয়েল পুররা

13

আপনি কোন শেল ব্যবহার করছেন তা উল্লেখ করবেন না, তবে বাশ-এ আপনি এটি করতে পারেন:

#!/bin/bash

if [[ -t 1 ]]; then
    # stdout is a terminal
else
    # stdout is not a terminal
fi

6

সোলারিসে, দেজে ক্লেটন এর পরামর্শ বেশিরভাগ ক্ষেত্রেই কাজ করে। -P পছন্দসইভাবে সাড়া দেয় না।

bash_redir_test.sh দেখতে দেখতে:

[[ -t 1 ]] && \
    echo 'STDOUT is attached to TTY'

[[ -p /dev/stdout ]] && \
    echo 'STDOUT is attached to a pipe'

[[ ! -t 1 && ! -p /dev/stdout ]] && \
    echo 'STDOUT is attached to a redirection'

লিনাক্সে, এটি দুর্দান্ত কাজ করে:

:$ ./bash_redir_test.sh
STDOUT is attached to TTY

:$ ./bash_redir_test.sh | xargs echo
STDOUT is attached to a pipe

:$ rm bash_redir_test.log 
:$ ./bash_redir_test.sh >> bash_redir_test.log

:$ tail bash_redir_test.log 
STDOUT is attached to a redirection

সোলারিসে:

:# ./bash_redir_test.sh
STDOUT is attached to TTY

:# ./bash_redir_test.sh | xargs echo
STDOUT is attached to a redirection

:# rm bash_redir_test.log 
bash_redir_test.log: No such file or directory

:# ./bash_redir_test.sh >> bash_redir_test.log
:# tail bash_redir_test.log 
STDOUT is attached to a redirection

:# 

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

1

নিম্নলিখিত কোডগুলি (কেবলমাত্র লিনাক্স ব্যাশ ৪.৪-তে পরীক্ষা করা) পোর্টেবল বা সুপারিশ করা উচিত নয় , তবে সম্পূর্ণতার জন্য এটি এখানে রয়েছে:

ls /proc/$$/fdinfo/* >/dev/null 2>&1 || grep -q 'flags: 00$' /proc/$$/fdinfo/0 && echo "pipe detected"

কেন জানি না, তবে মনে হয় ফাইল ব্যাখ্যায় "3" একরকম তৈরি করা হয়েছে যখন কোনও ব্যাশ ফাংশনটিতে STDIN পাইপ দেওয়া আছে।

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

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