ব্যাশটিতে কোনও ফাংশন বিদ্যমান কিনা তা নির্ধারণ করুন


187

বর্তমানে আমি কিছু ইউনিট পরীক্ষা করছি যা বাশ থেকে চালানো হয়। ইউনিট পরীক্ষাগুলি ব্যাশ স্ক্রিপ্টে শুরু, সম্পাদন এবং পরিষ্কার করা হয়। এই স্ক্রিপ্টটিতে নিয়মিত একটি init (), এক্সিকিউট () এবং ক্লিনআপ () ফাংশন থাকে। তবে এগুলি বাধ্যতামূলক নয়। আমি তাদের পরীক্ষা করতে চাই যদি সেগুলি সংজ্ঞায়িত হয় বা হয় না।

আমি আগে গ্রোপিং করে উত্সটি বপন করেছিলাম তবে এটি ভুল বলে মনে হয়েছিল। এটি করার জন্য আরও কি মার্জিত উপায় আছে?

সম্পাদনা করুন: নিম্নলিখিত স্নিপলেট একটি কবজ মত কাজ করে:

fn_exists()
{
    LC_ALL=C type $1 | grep -q 'shell function'
}

ধন্যবাদ। শেল লাইব্রেরি লোড করার সময় আমি শর্তসাপেক্ষে স্টাব্বড আউট সংস্করণগুলি সংজ্ঞায়িত করতে এটি ব্যবহার করি। fn_exists foo || foo() { :; }
হার্ভে

2
আপনি type -tএবং ব্যবহার করে গ্রেপ সংরক্ষণ করতে পারেন ==
রোল্যান্ড ওয়েবার

লোকেল অ-ইংরেজি থাকাকালীন কাজ করে না। ফিনিশ লোকাল ব্যবহার করার সময় এবং জার্মান ব্যবহার করার সময় type test_functionবলে । test_function on funktio.ist eine Funktion
কিমমো লেহ্টো

3
অ ইংরেজি লোকেল জন্য LC_ALL=Cresque করতে
gaRex

উত্তর:


191

আমি মনে করি আপনি 'টাইপ' কমান্ডটি সন্ধান করছেন। এটি আপনাকে জানাবে যে কোনও জিনিস কোনও ফাংশন, অন্তর্নির্মিত ফাংশন, বাহ্যিক আদেশ, বা কেবল সংজ্ঞায়িত নয়। উদাহরণ:

$ LC_ALL=C type foo
bash: type: foo: not found

$ LC_ALL=C type ls
ls is aliased to `ls --color=auto'

$ which type

$ LC_ALL=C type type
type is a shell builtin

$ LC_ALL=C type -t rvm
function

$ if [ -n "$(LC_ALL=C type -t rvm)" ] && [ "$(LC_ALL=C type -t rvm)" = function ]; then echo rvm is a function; else echo rvm is NOT a function; fi
rvm is a function

119
type -t $functionখাবারের টিকিট
অ্যালান বাতাস

4
আপনি উত্তর হিসাবে পোস্ট করেন নি কেন? :-)
টার্মিনাস

কারণ আমি আমার উত্তরটি প্রথম ঘোষনা করে পোস্ট করেছি :-)
অ্যালান উইন্ড

5
type [-t]চমৎকার বলতে কি একটি জিনিস, কিন্তু যখন পরীক্ষা যদি কিছু একটি ফাংশন, এটা ধীর যেহেতু আপনি নল আছে বা ব্যবহার ব্যাকটিক, উভয় যার একটি subprocess ডিম grep করতে।
লোয়েকি

1
আমি যদি ভুল না পাঠ করি তবে টাইপ ব্যবহার করে কোনও মিলিত ফাইল আছে কিনা তা যাচাই করতে একটি স্বীকৃত ন্যূনতম অ্যাক্সেস করতে হবে। @ লৌকি, আপনি বেশ সঠিক, তবে এটি হ'ল অপশনটি ন্যূনতম আউটপুট তৈরি করে এবং আপনি এখনও ত্রুটিযুক্তটি ব্যবহার করতে পারেন। সাব-প্রসেস ছাড়াই আপনি ফলাফল পেতে পারেন, যেমন type -t realpath > /dev/shm/tmpfile ; read < /dev/shm/tmpfile(খারাপ উদাহরণ)। তবে 0 টি ডিস্ক আইও থাকায় ডিক্লেয়ারটি সেরা উত্তর।
ওড়ওলোফিল

79
$ g() { return; }
$ declare -f g > /dev/null; echo $?
0
$ declare -f j > /dev/null; echo $?
1

1
আমার জন্য দুর্দান্ত কাজ। বিশেষত যেহেতু আমার শেলটিতে প্রকারের জন্য-টি পতাকা নেই ("" কমান্ড "টাইপটি নিয়ে আমার অনেক সমস্যা হয়েছিল)
ডেনিস

2
প্রকৃতপক্ষে, এটি zsh এও কাজ করে (আরসি স্ক্রিপ্টগুলির জন্য দরকারী), এবং ধরণের জন্য গ্রেপ করার প্রয়োজন হয় না।
লোয়েকি

2
@ ডেনিসহডাপের প্রয়োজন নেই type -t, পরিবর্তে আপনি প্রস্থান স্থিতির উপর নির্ভর করতে পারেন। আমি দীর্ঘদিন ধরে type program_name > /dev/null 2>&1 && program_name arguments || echo "error"দেখতে পেয়েছি যে আমি কিছু কল করতে সক্ষম হব কিনা। স্পষ্টতই type -tএবং উপরের পদ্ধতিটি প্রকারটি সনাক্ত করার অনুমতি দেয়, এটি কেবল "কলযোগ্য" কিনা।
0xC0000022L

@ 0xC0000022L যদি প্রোগ্রাম_নাম কোনও ফাংশন না হয়?
ডেভিড উইনিস্কি

2
@ 0xC0000022L আমি কীভাবে প্রস্থান স্থিতিটি ব্যবহার করে প্রোগ্রাম_নামটি কোনও ফাংশন তা আপনাকে জানাতে দেয় না সে সম্পর্কে নীটপিক করছিলাম, তবে এখন আমি মনে করি আপনি যে ঠিকানাটি লিখেছিলেন "স্পষ্টতই টাইপ-টি এবং উপরের পদ্ধতিটিও টাইপ সনাক্ত করতে দেয় , এটি কেবল "কলযোগ্য" কিনা তা নয় "" দুঃখিত।
ডেভিড উইনিস্কি

40

ঘোষণা যদি পরীক্ষার চেয়ে 10x দ্রুত হয় তবে এটি সুস্পষ্ট উত্তর বলে মনে হবে।

সম্পাদনা করুন: নীচে, -fবিকল্পটি বেসের সাথে অতিরিক্ত অতিরিক্ত, এটিকে ছাড়তে নির্দ্বিধায়। ব্যক্তিগতভাবে, কোন বিকল্পটি কোনটি করে তা মনে রাখতে আমার সমস্যা হয়, তাই আমি কেবল দুটিই ব্যবহার করি। -f ফাংশন প্রদর্শন করে এবং -F ফাংশনটির নাম দেখায়।

#!/bin/sh

function_exists() {
    declare -f -F $1 > /dev/null
    return $?
}

function_exists function_name && echo Exists || echo No such function

"-F" বিকল্পটি ঘোষণা করার ফলে এটি সম্পূর্ণ সামগ্রীর চেয়ে কেবলমাত্র পাওয়া ফাংশনটির নামই ফিরিয়ে আনবে।

/ Dev / নাল ব্যবহারের জন্য কোনও পরিমাপযোগ্য পারফরম্যান্স জরিমানা থাকা উচিত নয় এবং যদি এটি আপনাকে খুব চিন্তিত করে:

fname=`declare -f -F $1`
[ -n "$fname" ]    && echo Declare -f says $fname exists || echo Declare -f says $1 does not exist

বা আপনার নিজের অর্থহীন উপভোগের জন্য দুটি একত্রিত করুন। তারা উভয় কাজ.

fname=`declare -f -F $1`
errorlevel=$?
(( ! errorlevel )) && echo Errorlevel says $1 exists     || echo Errorlevel says $1 does not exist
[ -n "$fname" ]    && echo Declare -f says $fname exists || echo Declare -f says $1 does not exist

2
'-F' বিকল্পটি নিরর্থক।
রাজিশ

3
-Fবিকল্প দেস (বহনযোগ্যতা জন্য দরকারী) zsh নেই অস্তিত্ব
Lloeki

-Fএছাড়াও সত্যই প্রয়োজন হয় না: এটি কেবল ফাংশন সংজ্ঞা / বডি দমন করে বলে মনে হচ্ছে।
14

1
@ ব্লুয়েড এটি প্রয়োজনীয় নাও হতে পারে তবে এটি অত্যন্ত কাম্য। কোনও ফাইল ব্যবহার করে উপস্থিত রয়েছে কিনা তা আপনি পরীক্ষা করতে পারেন cat "$fn" | wc -c? Zsh হিসাবে, যদি ব্যাশ ট্যাগ আপনাকে সন্ধান না করে তবে নিজেই প্রশ্নটি থাকা উচিত। "ব্যাশটিতে কোনও ফাংশন বিদ্যমান কিনা তা নির্ধারণ করুন"। আমি আরও উল্লেখ করব, যে -Fবিকল্পটি zsh তে বিদ্যমান না থাকলেও এটি কোনও ত্রুটি সৃষ্টি করে না, সুতরাং -f এবং -F উভয় ব্যবহারের ফলে চেকটি zsh এবং bash উভয় ক্ষেত্রেই সফল হতে দেয় যা অন্যথায় তা না হয় ।
ওড়ওলোফিল

@ ওড়ওলোফাইল -Fভাসমান পয়েন্ট সংখ্যাগুলির জন্য zsh এ ব্যবহৃত হয়। -Fব্যাশকে কেন ব্যবহার করা আরও উন্নত করে? আমি ইমপ্রেশন পেয়েছি যা ব্যাশে declare -fএকই কাজ করে (রিটার্ন কোড সম্পর্কিত)।
নীল রঙের

18

অন্যান্য সমাধান এবং মন্তব্যগুলি থেকে ধার করে আমি এটি নিয়ে এসেছি:

fn_exists() {
  # appended double quote is an ugly trick to make sure we do get a string -- if $1 is not a known command, type does not output anything
  [ `type -t $1`"" == 'function' ]
}

হিসাবে ব্যবহার ...

if ! fn_exists $FN; then
    echo "Hey, $FN does not exist ! Duh."
    exit 2
fi

প্রদত্ত আর্গুমেন্টটি কোনও ফাংশন কিনা তা এটি পরীক্ষা করে এবং পুনর্নির্দেশগুলি এবং অন্যান্য গ্রেপিং এড়ায়।


চমৎকার, গ্রুপ থেকে আমার ফেভ! আপনি কি যুক্তির আশেপাশে ডাবল উদ্ধৃতি চান না? যেমনটি[ $(type -t "$1")"" == 'function' ]
কুইকশিফ্টিন

ধন্যবাদ @ কুইকশিফটিন; আমি জানি না আমি এই ডাবল উক্তিগুলি চাই কিনা, তবে আপনি সম্ভবত সঠিক, যদিও .. এমন একটি নাম দিয়ে কোনও ফাংশনও ঘোষণা করা যেতে পারে যা উদ্ধৃত করা দরকার?
গ্রেগরি জোসেফ

4
আপনি ব্যাশ ব্যবহার করছেন, [[...]]পরিবর্তে ব্যবহার করুন [...]এবং উদ্ধৃতি হ্যাক থেকে মুক্তি পান। এছাড়াও ব্যাকটিক্স কাঁটাচামচ, যা ধীর। declare -f $1 > /dev/nullপরিবর্তে ব্যবহার করুন।
লোয়েকি

3
খালি যুক্তি, উদ্ধৃতি হ্রাস এবং '=' পিক্সিক্স সামঞ্জস্যপূর্ণ সাম্য ব্যবহার করে ত্রুটিগুলি এড়ানো এটিকে নিরাপদে হ্রাস করা যেতে পারে :: fn_exists() { [ x$(type -t $1) = xfunction ]; }
qneill

10

একটি পুরানো পোস্ট ড্রেজিং ... তবে আমি সম্প্রতি এটি ব্যবহার করেছি এবং এর সাথে বর্ণিত উভয় বিকল্পের পরীক্ষা করেছি:

test_declare () {
    a () { echo 'a' ;}

    declare -f a > /dev/null
}

test_type () {
    a () { echo 'a' ;}
    type a | grep -q 'is a function'
}

echo 'declare'
time for i in $(seq 1 1000); do test_declare; done
echo 'type'
time for i in $(seq 1 100); do test_type; done

এটি উত্পন্ন:

real    0m0.064s
user    0m0.040s
sys     0m0.020s
type

real    0m2.769s
user    0m1.620s
sys     0m1.130s

দ্রুত ঘোষিত হেলুভলোট!


1
এটি test_type_nogrep () { a () { echo 'a' ;}; local b=$(type a); c=${b//is a function/}; [ $? = 0 ] && return 1 || return 0; }
গ্রেপ

@ ক্নিল আমি আমার উত্তরে কিছুটা আরও বিস্তৃত পরীক্ষা করেছি ,
জার্নো

পাইপ সবচেয়ে ধীরতম উপাদান। এই পরীক্ষার তুলনা হয় না typeএবং declare। এর সাথে তুলনা করা type | grepহয় declare। এটি একটি বড় পার্থক্য।
kyb

7

আউটপুট বা প্রস্থান কোড চেক করতে এটি 'ডিক্লেয়ার' ব্যবহার করে এটি ফোটে।

আউটপুট শৈলী:

isFunction() { [[ "$(declare -Ff "$1")" ]]; }

ব্যবহার:

isFunction some_name && echo yes || echo no

যাইহোক, যদি মেমরিটি পরিবেশন করে তবে আউটপুট প্রতিস্থাপনের তুলনায় নালকে পুনর্নির্দেশ করা দ্রুত হয় (কথা বললে, ভয়ঙ্কর এবং পুরানো `সেমিডি` পদ্ধতিটি নিষিদ্ধ করা উচিত এবং এর পরিবর্তে $ (সেন্টিমিটার) ব্যবহার করা উচিত)) এবং যেহেতু রিটার্নগুলি সত্য / মিথ্যা ঘোষণা করলে / পাওয়া যায় নি, এবং ফাংশনগুলি ফাংশনে শেষ কমান্ডের প্রস্থান কোডটি ফেরত দেয় যাতে একটি স্পষ্ট ফেরত সাধারণত প্রয়োজন হয় না এবং যেহেতু ত্রুটি কোডটি পরীক্ষা করা একটি স্ট্রিংয়ের মান (এমনকি নাল স্ট্রিং) যাচাই করার চেয়েও দ্রুত হয়:

প্রস্থান স্টাইল থেকে প্রস্থান করুন:

isFunction() { declare -Ff "$1" >/dev/null; }

এটি সম্ভবত আপনি যেমন পেতে পারেন তেমন সুসংহত এবং সৌম্য।


3
সর্বাধিক সংক্ষিপ্ত ব্যবহারের জন্যisFunction() { declare -F "$1"; } >&-
নীল

3
isFunction() { declare -F -- "$@" >/dev/null; }আমার প্রস্তাবনা। এটি নামের তালিকায় পাশাপাশি কাজ করে (সমস্ত ফাংশন হলেই সাফল্য লাভ করে) এবং নামটি শুরু করার ক্ষেত্রে কোনও সমস্যা দেয় না -এবং আমার পাশে ( bash৪.২.২৫) declareসর্বদা ব্যর্থ হয় যখন আউটপুট বন্ধ থাকে >&-, কারণ এটি নাম লিখতে পারে না সেই ক্ষেত্রে
টিনো

এবং দয়া করে সচেতন হন, যা echoকিছু প্ল্যাটফর্মে কখনও কখনও "বিঘ্নিত সিস্টেম কল" এর সাথে ব্যর্থ হতে পারে । noসেক্ষেত্রে "চেক অ্যান্ড অ্যান্ডো ইকো হ্যাঁ || প্রতিধ্বনি কোনও" এখনও checkসত্য না হলে আউটপুট দিতে পারে।
টিনো

7

বিভিন্ন সমাধান পরীক্ষা করা:

#!/bin/bash

test_declare () {
    declare -f f > /dev/null
}

test_declare2 () {
    declare -F f > /dev/null
}

test_type () {
    type -t f | grep -q 'function'
}

test_type2 () {
     [[ $(type -t f) = function ]]
}

funcs=(test_declare test_declare2 test_type test_type2)

test () {
    for i in $(seq 1 1000); do $1; done
}

f () {
echo 'This is a test function.'
echo 'This has more than one command.'
return 0
}
post='(f is function)'

for j in 1 2 3; do

    for func in ${funcs[@]}; do
        echo $func $post
        time test $func
        echo exit code $?; echo
    done

    case $j in
    1)  unset -f f
        post='(f unset)'
        ;;
    2)  f='string'
        post='(f is string)'
        ;;
    esac
done

আউটপুট যেমন:

টেস্ট_ডেক্লেয়ার (এফ ফাংশন)

আসল 0m0,055s ব্যবহারকারী 0m0,041 গুলি 0 ম0,004 গুলি প্রস্থান করুন 0 প্রস্থান কোড

টেস্ট_ডেক্লেয়ার 2 (এফ ফাংশন)

আসল 0m0,042 গুলি ব্যবহারকারীর 0m0,022 গুলি 0 ম0,017 গুলি প্রস্থান কোড 0 টি ys

পরীক্ষার_প্রকার (এফ ফাংশন)

আসল 0 এম 2,200 এর ব্যবহারকারীর 0 এম 1,619 গুলি 0 এম 1,008 এস প্রস্থান কোড 0 সিক্স

পরীক্ষা_প্রকার 2 (চ ক্রিয়াকলাপ)

বাস্তব 0m0,746s ব্যবহারকারীর 0m0,534s s0 0m0,237 গুলি প্রস্থান কোড 0

টেস্ট_ডেক্লেয়ার (এফ সেট না করা)

আসল 0m0,040s ব্যবহারকারী 0m0,029 গুলি 0 ম0,010 গুলি প্রস্থান করুন কোড 1

টেস্ট_ডেক্লেয়ার 2 (এফ সেট না করা)

প্রকৃত 0m0,038s ব্যবহারকারী 0 এম 0,038 গুলি 0 ম0,000 এস প্রস্থান কোড 1 টি দেখতে পান

পরীক্ষা_প্রকার (এফ সেট না করা)

আসল 0 এম 2,438 এর ব্যবহারকারী 0 এম 1,678 গুলি 0 মি 1,045 এস প্রস্থান কোড 1 টি

পরীক্ষা_প্রকার 2 (এফ সেট না করা)

আসল 0m0,805s ব্যবহারকারীর 0m0,541 গুলি 0 ম0,274 এর প্রস্থান কোড 1 টি

পরীক্ষা_ডেক্লেয়ার (চ স্ট্রিং)

আসল 0m0,043s ব্যবহারকারী 0m0,034 গুলি 0 ম0,007 গুলি প্রস্থান করুন 1 প্রস্থান কোড 1

পরীক্ষা_ডেক্লেয়ার 2 (চ স্ট্রিং)

আসল 0m0,039s ব্যবহারকারী 0m0,035 এর s0 0m0,003 এস প্রস্থান কোড 1

পরীক্ষা_প্রকার (চ স্ট্রিং)

আসল 0 এম 2,394s ব্যবহারকারী 0 এম 1,679 গুলি 0 মি 1,035 গুলি প্রস্থান করুন কোড 1

পরীক্ষা_প্রকার 2 (চ স্ট্রিং)

আসল 0m0,851s ব্যবহারকারীর 0m0,554s s0 0m0,294s প্রস্থান কোড 1

তাই declare -F fসেরা সমাধান বলে মনে হচ্ছে।


এখানে মনোযোগ দিন: declare -F fচ zsh এ অস্তিত্ব না থাকলে শূন্যের মান ফিরিয়ে দেয় না, তবে হ্যাঁ। এটি ব্যবহারে সতর্কতা অবলম্বন করুন। declare -f fঅন্যদিকে, স্টাডাউট (যা বিরক্তিকর হতে পারে ...) এর ফাংশনটির সংজ্ঞা সংযুক্তি হিসাবে প্রত্যাশার মতো কাজ করে
মনোলো ভিলেলা

1
আপনি কি চেষ্টা করেছেন test_type3 () { [[ $(type -t f) = function ]] ; }স্থানীয় ভেরি (যদিও <10%) সংজ্ঞায়নের জন্য একটি প্রান্তিক ব্যয় আছে
অলিভার

4

অন্য উত্তর সম্পর্কে আমার মন্তব্য থেকে (যা আমি এই পৃষ্ঠায় ফিরে আসার পরে মিস করছি)

$ fn_exists() { test x$(type -t $1) = xfunction; }
$ fn_exists func1 && echo yes || echo no
no
$ func1() { echo hi from func1; }
$ func1
hi from func1
$ fn_exists func1 && echo yes || echo no
yes


2

আমি এটিকে উন্নত করব:

fn_exists()
{
    type $1 2>/dev/null | grep -q 'is a function'
}

এবং এটি এর মতো ব্যবহার করুন:

fn_exists test_function
if [ $? -eq 0 ]; then
    echo 'Function exists!'
else
    echo 'Function does not exist...'
fi


2

গ্রাগরি জোসেফের কাছ থেকে আমি সমাধানটি বিশেষত পছন্দ করেছি

তবে "ডাবল কোট কুরুচিপূর্ণ কৌশল" কাটিয়ে উঠতে আমি এটি কিছুটা সংশোধন করেছি:

function is_executable()
{
    typeset TYPE_RESULT="`type -t $1`"

    if [ "$TYPE_RESULT" == 'function' ]; then
        return 0
    else
        return 1
    fi
}

0

কোনও বাহ্যিক আদেশ ছাড়াই 'টাইপ' ব্যবহার করা সম্ভব, তবে আপনাকে এটি দুটি বার কল করতে হবে, সুতরাং এটি এখনও 'ডিক্লেয়ার' সংস্করণের দ্বিগুণ হয়ে ধীরে ধীরে শেষ হয়:

test_function () {
        ! type -f $1 >/dev/null 2>&1 && type -t $1 >/dev/null 2>&1
}

প্লাস এটি পসিক্স শ তে কাজ করে না, সুতরাং এটি ট্রিভিয়া ছাড়া সম্পূর্ণ নিরর্থক!


পরীক্ষা_প্রকার_নোগ্রেপ () {ক () {প্রতিধ্বনি 'এ';}; স্থানীয় খ = $ (টাইপ এ); সি = $ {বি // একটি ফাংশন /}; [$? = 0] && ফেরত 1 || প্রত্যাবর্তন 0; } - কুইনিল
অ্যালেক্সেক্স রোচে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.