বাশ স্ক্রিপ্টে কীভাবে আর্গুমেন্টগুলি পুনরায় করা যায়


899

আমার একটি জটিল কমান্ড রয়েছে যা আমি একটি শেল / বাশ স্ক্রিপ্ট তৈরি করতে চাই। আমি এটি $1সহজেই পদে লিখতে পারি :

foo $1 args -o $1.ext

আমি স্ক্রিপ্টে একাধিক ইনপুট নামগুলি পাস করতে সক্ষম হতে চাই। এটি করার সঠিক উপায় কী?

এবং অবশ্যই, আমি ফাইলের নামগুলিতে ফাঁকা স্থানগুলি হ্যান্ডেল করতে চাই।


67
এফওয়াইআই, সর্বদা উদ্ধৃতিগুলির মধ্যে পরামিতিগুলি রাখা ভাল ধারণা। আপনি কখনই জানেন না কখন কোনও পার্মে এমবেডড স্পেস থাকতে পারে।
ডেভিড আর ট্রিবিলে

উত্তর:


1478

"$@"সমস্ত যুক্তি উপস্থাপন করতে ব্যবহার করুন :

for var in "$@"
do
    echo "$var"
done

এটি প্রতিটি যুক্তির পুনরাবৃত্তি করবে এবং আলাদা লাইনে মুদ্রণ করবে। ed @ এর মতো আচরণ করে except * ব্যতীত যখন উদ্ধৃতি দেওয়া হয় তখন আর্গুমেন্টগুলির মধ্যে ফাঁকা স্থানগুলি ঠিকঠাক হয়ে গেলে:

sh test.sh 1 2 '3 4'
1
2
3 4

38
ঘটনাক্রমে, অন্যান্য বৈশিষ্ট্যগুলির মধ্যে একটি "$@"হ'ল এটি কোনও স্থানে প্রসারিত হয় যখন কোনও অবস্থানীয় পরামিতি থাকে না যেখানে "$*"খালি স্ট্রিংয়ে প্রসারিত হয় - এবং হ্যাঁ, কোনও যুক্তি এবং একটি খালি যুক্তির মধ্যে পার্থক্য নেই। দেখুন ${1:+"$@"} in / বিন / sh`
জোনাথন লেফলার

9
নোট করুন যে ফাংশনটিতে সমস্ত আর্গুমেন্ট অ্যাক্সেস করার জন্য এই স্বরলিপিটি শেল ফাংশনেও ব্যবহার করা উচিত।
জোনাথন লেফলার

দ্বিগুণ উদ্ধৃতিগুলি ফেলে: $varআমি যুক্তিগুলি কার্যকর করতে সক্ষম হয়েছি।
ইনিস্ট

দ্বিতীয় যুক্তি থেকে কীভাবে শুরু করব? মানে আমার এটি দরকার তবে সর্বদা দ্বিতীয় যুক্তি থেকে শুরু করুন, এটি, 1 এড়িয়ে যান।
m4l490n

4
@ m4l490n: shiftছুড়ে ফেলে $1এবং পরবর্তী সমস্ত উপাদানকে নীচে নামিয়ে দেয়।
এমসাল্টাররা

239

একটি এখন মোছা এর লেখা উত্তর দ্বারা VonC

রবার্ট গাম্বলের সুসংযোগ উত্তরটি সরাসরি প্রশ্নের সাথে ডিল করে। এটি শূন্যস্থান সহ ফাইলের নাম সহ কিছু ইস্যুতে প্রশস্ত করে।

আরও দেখুন: bin {1: + "$ @"} ইন / বিন / শ মধ্যে

বেসিক থিসিস: "$@" সঠিক, এবং $*(উদ্ধৃত) প্রায় সর্বদা ভুল is এটি কারণ "$@"সূক্ষ্মভাবে কাজ করে যখন যুক্তিগুলিতে ফাঁক থাকে এবং $*যখন না হয় তখন একইভাবে কাজ করে । কিছু পরিস্থিতিতে, "$*"ঠিক আছে তবে "$@"সাধারণত (তবে সর্বদা নয়) একই জায়গায় কাজ করে। উদ্ধৃত, $@এবং $*সমতুল্য (এবং প্রায় সর্বদা ভুল)।

সুতরাং, এর মধ্যে পার্থক্য কি $*, $@, "$*", এবং "$@"? এগুলি সমস্ত 'শেলের সমস্ত যুক্তি' সম্পর্কিত, তবে তারা বিভিন্ন জিনিস করে। যখন উদ্ধৃতিহীন, $*এবং $@একই জিনিস করুন। তারা প্রতিটি 'শব্দ' (অ-সাদা অংশের ক্রম) পৃথক যুক্তি হিসাবে বিবেচনা করে। উদ্ধৃত ফর্মগুলি একেবারে আলাদা, যদিও: "$*"যুক্তি তালিকার একটি একক স্থান-বিভাজিত স্ট্রিং "$@"হিসাবে বিবেচনা করে , যেখানে আর্গুমেন্টগুলি ঠিক ঠিক একইভাবে আচরণ করে যেমন কমান্ড লাইনে নির্দিষ্ট করার সময়। "$@"কোনও অবস্থানগত যুক্তি না থাকলে কিছুতেই প্রসারিত হয়; "$*"একটি খালি স্ট্রিংয়ে প্রসারিত - এবং হ্যাঁ, এটির পার্থক্য রয়েছে, যদিও এটি উপলব্ধি করা শক্ত। (অ-মানক) কমান্ড প্রবর্তনের পরে নীচে আরও তথ্য দেখুন al

সেকেন্ডারি থিসিস: আপনার যদি ফাঁকা জায়গা দিয়ে তর্কগুলি প্রক্রিয়াকরণের দরকার হয় এবং তারপরে এগুলি অন্য কমান্ডগুলিতে প্রেরণ করা প্রয়োজন, তবে আপনাকে সহায়তার জন্য কখনও কখনও আপনার অ-মানক সরঞ্জামের প্রয়োজন হয়। (অথবা আপনার সাবধানতার সাথে অ্যারে ব্যবহার করা উচিত: এর সাথে "${array[@]}"অ্যালোগুলি আচরণ করে "$@"))

উদাহরণ:

    $ mkdir "my dir" anotherdir
    $ ls
    anotherdir      my dir
    $ cp /dev/null "my dir/my file"
    $ cp /dev/null "anotherdir/myfile"
    $ ls -Fltr
    total 0
    drwxr-xr-x   3 jleffler  staff  102 Nov  1 14:55 my dir/
    drwxr-xr-x   3 jleffler  staff  102 Nov  1 14:55 anotherdir/
    $ ls -Fltr *
    my dir:
    total 0
    -rw-r--r--   1 jleffler  staff  0 Nov  1 14:55 my file

    anotherdir:
    total 0
    -rw-r--r--   1 jleffler  staff  0 Nov  1 14:55 myfile
    $ ls -Fltr "./my dir" "./anotherdir"
    ./my dir:
    total 0
    -rw-r--r--   1 jleffler  staff  0 Nov  1 14:55 my file

    ./anotherdir:
    total 0
    -rw-r--r--   1 jleffler  staff  0 Nov  1 14:55 myfile
    $ var='"./my dir" "./anotherdir"' && echo $var
    "./my dir" "./anotherdir"
    $ ls -Fltr $var
    ls: "./anotherdir": No such file or directory
    ls: "./my: No such file or directory
    ls: dir": No such file or directory
    $

কেন যে কাজ করে না? এটি কার্যকর হয় না কারণ শেল প্রক্রিয়াগুলি ভেরিয়েবলগুলি প্রসারিত করার আগে উদ্ধৃতি দেয়। সুতরাং, শ্বেতটি এম্বেড করা উদ্ধৃতিগুলিতে মনোযোগ দেওয়ার জন্য $varআপনাকে ব্যবহার করতে হবে eval:

    $ eval ls -Fltr $var
    ./my dir:
    total 0
    -rw-r--r--   1 jleffler  staff  0 Nov  1 14:55 my file

    ./anotherdir:
    total 0
    -rw-r--r--   1 jleffler  staff  0 Nov  1 14:55 myfile
    $ 

আপনার কাছে ফাইলের নাম যেমন " He said, "Don't do this!"" (কোট এবং ডাবল কোট এবং স্পেস সহ) থাকে তখন এটি সত্যই জটিল হয়ে ওঠে।

    $ cp /dev/null "He said, \"Don't do this!\""
    $ ls
    He said, "Don't do this!"       anotherdir                      my dir
    $ ls -l
    total 0
    -rw-r--r--   1 jleffler  staff    0 Nov  1 15:54 He said, "Don't do this!"
    drwxr-xr-x   3 jleffler  staff  102 Nov  1 14:55 anotherdir
    drwxr-xr-x   3 jleffler  staff  102 Nov  1 14:55 my dir
    $ 

শেলগুলি (এগুলির সবগুলি) এ জাতীয় স্টাফগুলি পরিচালনা করা বিশেষত সহজ করে না, তাই (ইউজার্সে যথেষ্ট) অনেকগুলি ইউনিক্স প্রোগ্রামগুলি পরিচালনা করার পক্ষে ভাল কাজ করে না। ইউনিক্সে, একটি ফাইলের নাম (একক উপাদান) স্ল্যাশ এবং NUL ব্যতীত যে কোনও অক্ষর ধারণ করতে পারে '\0'। যাইহোক, শেলগুলি কোনও শূন্যস্থান বা নিউলাইন বা ট্যাবগুলিকে কোনও পথের নামে কোথাও উত্সাহ দেয়। স্ট্যান্ডার্ড ইউনিক্স ফাইলের নামগুলিতে স্পেস ইত্যাদি থাকে না কেন এটি is

ফাঁকা জায়গা এবং অন্যান্য ঝামেলাযুক্ত অক্ষরগুলি ধারণ করতে পারে এমন ফাইলের নামগুলির সাথে কথা বলার সময়, আপনাকে অত্যন্ত সতর্কতা অবলম্বন করতে হবে এবং আমি অনেক আগেই পেয়েছি যে আমার এমন একটি প্রোগ্রামের দরকার ছিল যা ইউনিক্সের উপর স্ট্যান্ডার্ড নয়। আমি এটি বলি escape(সংস্করণ 1.1 1989-08-23T16: 01: 45Z তারিখের ছিল)।

এখানে ব্যবহারের একটি উদাহরণ রয়েছে escape- এসসিসি নিয়ন্ত্রণ ব্যবস্থা সহ। এটি একটি কভার স্ক্রিপ্ট যা একটি delta(চিন্তাভাবনা চেক-ইন ) এবং একটি get(চিন্তাভাবনা চেক-আউট ) করে does বিভিন্ন যুক্তি, বিশেষত -y(কারণ আপনি কেন পরিবর্তন করেছেন) ফাঁকা এবং নিউলাইনগুলি ধারণ করে। নোট করুন যে স্ক্রিপ্টটি 1992 সালের, তাই এটি $(cmd ...)স্বরলিপিটির পরিবর্তে ব্যাক-টিক ব্যবহার #!/bin/shকরে এবং প্রথম লাইনে ব্যবহার করে না use

:   "@(#)$Id: delget.sh,v 1.8 1992/12/29 10:46:21 jl Exp $"
#
#   Delta and get files
#   Uses escape to allow for all weird combinations of quotes in arguments

case `basename $0 .sh` in
deledit)    eflag="-e";;
esac

sflag="-s"
for arg in "$@"
do
    case "$arg" in
    -r*)    gargs="$gargs `escape \"$arg\"`"
            dargs="$dargs `escape \"$arg\"`"
            ;;
    -e)     gargs="$gargs `escape \"$arg\"`"
            sflag=""
            eflag=""
            ;;
    -*)     dargs="$dargs `escape \"$arg\"`"
            ;;
    *)      gargs="$gargs `escape \"$arg\"`"
            dargs="$dargs `escape \"$arg\"`"
            ;;
    esac
done

eval delta "$dargs" && eval get $eflag $sflag "$gargs"

(এই দিনগুলিতে আমি সম্ভবত পালানোর বিষয়টি পুরোপুরিভাবে ব্যবহার করব না - -eযুক্তি দিয়ে এটির দরকার হয় না - তবে সামগ্রিকভাবে এটি আমার সহজ স্ক্রিপ্টগুলি ব্যবহার করে escape))

escapeপ্রোগ্রাম কেবল বরং ভালো, তার আর্গুমেন্ট আউটপুট echo , কিন্তু এটি নিশ্চিত করে যে আর্গুমেন্ট সাথে ব্যবহারের জন্য সুরক্ষিত হয় eval(এর এক স্তর eval; আমি একটি প্রোগ্রাম যা দূরবর্তী শেল সঞ্চালনের করেনি আছে, এবং যে আউটপুট অব্যাহতি প্রয়োজন escape)।

    $ escape $var
    '"./my' 'dir"' '"./anotherdir"'
    $ escape "$var"
    '"./my dir" "./anotherdir"'
    $ escape x y z
    x y z
    $ 

আমার আরেকটি প্রোগ্রাম বলা হয়েছে alযা প্রতি লাইন প্রতি তার আর্গুমেন্টগুলি তালিকাভুক্ত করে (এবং এটি আরও প্রাচীন: সংস্করণ 1.1 তারিখ 1987-01-27T14: 35: 49)। স্ক্রিপ্টগুলি ডিবাগ করার সময় এটি সর্বাধিক উপকারী, কারণ কমান্ডে আসলে কী আর্গুমেন্টগুলি দেওয়া হয় তা দেখার জন্য এটি একটি কমান্ড লাইনে প্লাগ করা যায়।

    $ echo "$var"
    "./my dir" "./anotherdir"
    $ al $var
    "./my
    dir"
    "./anotherdir"
    $ al "$var"
    "./my dir" "./anotherdir"
    $

[ যুক্ত: এবং এখন বিভিন্ন "$@"স্বরলিপিগুলির মধ্যে পার্থক্য দেখানোর জন্য , এখানে আরও একটি উদাহরণ দেওয়া হল:

$ cat xx.sh
set -x
al $@
al $*
al "$*"
al "$@"
$ sh xx.sh     *      */*
+ al He said, '"Don'\''t' do 'this!"' anotherdir my dir xx.sh anotherdir/myfile my dir/my file
He
said,
"Don't
do
this!"
anotherdir
my
dir
xx.sh
anotherdir/myfile
my
dir/my
file
+ al He said, '"Don'\''t' do 'this!"' anotherdir my dir xx.sh anotherdir/myfile my dir/my file
He
said,
"Don't
do
this!"
anotherdir
my
dir
xx.sh
anotherdir/myfile
my
dir/my
file
+ al 'He said, "Don'\''t do this!" anotherdir my dir xx.sh anotherdir/myfile my dir/my file'
He said, "Don't do this!" anotherdir my dir xx.sh anotherdir/myfile my dir/my file
+ al 'He said, "Don'\''t do this!"' anotherdir 'my dir' xx.sh anotherdir/myfile 'my dir/my file'
He said, "Don't do this!"
anotherdir
my dir
xx.sh
anotherdir/myfile
my dir/my file
$

লক্ষ্য করুন যে কিছুই কমান্ড লাইনের ওপরে *এবং আসল ফাঁকাগুলি সংরক্ষণ করে না */*। এছাড়াও, নোট করে আপনি শেলটিতে 'কমান্ড লাইন আর্গুমেন্ট' পরিবর্তন করতে পারেন:

set -- -new -opt and "arg with space"

এটি ' -new', ' -opt', ' and' এবং ' arg with space' 4 টি বিকল্প সেট করে ।
]

হুম, এটি বেশ দীর্ঘ উত্তর - সম্ভবত এক্সাইজেসিসই এটি আরও ভাল শব্দ। escapeঅনুরোধের জন্য উপলব্ধ সোর্স কোড (জিমেইল ডট কম এ প্রথম নাম ডট লাস্টনেমে ইমেল) to এর উত্স কোডটি alঅবিশ্বাস্যভাবে সহজ:

#include <stdio.h>
int main(int argc, char **argv)
{
    while (*++argv != 0)
        puts(*argv);
    return(0);
}

এখানেই শেষ. এটি test.shরবার্ট গাম্বলি যে স্ক্রিপ্টটি দেখিয়েছিল তার সমান এবং এটি শেল ফাংশন হিসাবে লেখা যেতে পারে (তবে শর্নের কার্যকারিতা বোর্ন শেলের স্থানীয় সংস্করণে উপস্থিত ছিল না যখন আমি প্রথম লিখেছিলাম al)।

এছাড়াও মনে রাখবেন যে আপনি alএকটি সাধারণ শেল স্ক্রিপ্ট হিসাবে লিখতে পারেন :

[ $# != 0 ] && printf "%s\n" "$@"

শর্তসাপেক্ষে প্রয়োজনীয় যাতে কোনও আর্গুমেন্ট পাস না করে এটি কোনও আউটপুট তৈরি করে না। printfকমান্ডটি কেবল বিন্যাসের স্ট্রিং আর্গুমেন্ট সহ একটি ফাঁকা রেখা তৈরি করবে, তবে সি প্রোগ্রামটি কিছুই তৈরি করে না।


132

লক্ষ্য করুন রবার্ট উত্তরটি সঠিক, এবং এটি কাজ করে shপাশাপাশি। আপনি (বহনযোগ্যভাবে) এটিকে আরও আরও সরল করতে পারেন:

for i in "$@"

সমান:

for i

অর্থাৎ আপনার কিছু লাগবে না!

পরীক্ষা করা ( $কমান্ড প্রম্পট):

$ set a b "spaces here" d
$ for i; do echo "$i"; done
a
b
spaces here
d
$ for i in "$@"; do echo "$i"; done
a
b
spaces here
d

আমি প্রথম এটি সম্পর্কে কার্নিগান এবং পাইকের দ্বারা ইউনিক্স প্রোগ্রামিং পরিবেশে পড়েছি ।

ইন bash, help forদস্তাবেজগুলি:

for NAME [in WORDS ... ;] do COMMANDS; done

যদি 'in WORDS ...;'উপস্থিত না থাকে তবে 'in "$@"'ধরে নেওয়া হয়।


4
আমি একমত নই ক্রিপ্টিক "$@"মানে কী তা একজনকে জানতে হবে এবং একবার আপনি কী for iঅর্থ বুঝতে পারলেন, এটি এর চেয়ে কম পাঠযোগ্য নয় for i in "$@"
অলোক সিংহল

10
আমি জোর দিয়ে বলিনি যে for iএটি কীস্ট্রোকগুলি সংরক্ষণ করে better আমি পাঠযোগ্যতা তুলনায় for iএবং for i in "$@"
অলোক সিংহল

এটিই আমি সন্ধান করছিলাম - লুপগুলিতে you @ এর এই অনুমানটিকে তারা কী বলে? Reference @ রেফারেন্সটি ব্যবহার না করার কোনও প্রতিকূলতা আছে?
কোডেনিনজা

58

সাধারণ ক্ষেত্রে আপনি ব্যবহার করতে পারেন shift। এটি আর্গুমেন্ট তালিকাটিকে একটি সারিটির মতো আচরণ করে। প্রতিটি shiftপ্রথম যুক্তি ছুঁড়ে ফেলে এবং বাকি প্রতিটি আর্গুমেন্টের সূচি হ্রাস করা হয়।

#this prints all arguments
while test $# -gt 0
do
    echo "$1"
    shift
done

আমি মনে করি এই উত্তরটি আরও ভাল কারণ আপনি যদি shiftলুপের জন্য এটি করেন তবে সেই উপাদানটি এখনও অ্যারের অংশ, যদিও shiftএটি প্রত্যাশার সাথে কাজ করে।
ডেভিডজি

2
নোট করুন যে আপনার echo "$1"আর্গুমেন্ট স্ট্রিংয়ের মান ব্যবধানে সংরক্ষণ করার জন্য ব্যবহার করা উচিত । এছাড়াও, (একটি ছোটখাটো সমস্যা) এটি ধ্বংসাত্মক: আপনি যদি এগুলি সমস্ত সরিয়ে নিয়ে যান তবে আপনি তর্কগুলি পুনরায় ব্যবহার করতে পারবেন না। প্রায়শই, এটি কোনও সমস্যা নয় - আপনি কেবল একবারই যুক্তি তালিকার প্রক্রিয়া করুন।
জোনাথন লেফলার

1
সম্মত হন যে স্থানান্তরটি আরও ভাল, কারণ "-o আউটপুটফাইলে" এর মতো পতাকা যুক্তিগুলি প্রসেস করার জন্য আপনার কাছে একটি সুইচ ক্ষেত্রে দুটি আর্গুমেন্ট ধরার সহজ উপায় রয়েছে।
বাক্সিসিমো

অন্যদিকে, আপনি যদি পতাকা যুক্তিগুলি বিশ্লেষণ করতে শুরু করেন তবে আপনি
বাশের

4
এই সমাধানটি যদি আপনার কয়েকটি দম্পতির প্যারামিটার-মান প্রয়োজন হয় তবে এটি আরও ভাল example উদাহরণস্বরূপ --file myfile.txt , the 1 প্যারামিটার হয়, $ 2 এর মান হয় এবং যখন আপনি অন্য যুক্তি এড়াতে চান তখন আপনি দুবার শিফট কল করবেন
ড্যানিয়েল লিকিট্রা

16

আপনি এগুলি অ্যারে উপাদান হিসাবেও অ্যাক্সেস করতে পারেন, উদাহরণস্বরূপ যদি আপনি সেগুলির মাধ্যমে পুনরাবৃত্তি করতে না চান

argc=$#
argv=("$@")

for (( j=0; j<argc; j++ )); do
    echo "${argv[j]}"
done

5
আমি বিশ্বাস করি যে রেখাটি আরগভি = ($ @) হওয়া উচিত আর্গভ = ("$ @") স্পেস সহ অন্যান্য বুদ্ধিমান
আরোগুলি

আমি নিশ্চিত করেছি সঠিক বাক্য গঠনটি আরগভি = ("$ @")। যদি আপনার কোন উদ্ধৃত পরামিতি থাকে তবে আপনি সর্বশেষ মান পাবেন না। উদাহরণস্বরূপ আপনি যদি এমন কিছু ব্যবহার করেন ./my-script.sh param1 "param2 is a quoted param": - আরগভি = ($ @) ব্যবহার করে আপনি [প্যারাম 1, প্যারাম 2], - আরজিভি = ("$ @") ব্যবহার করে পাবেন [প্যারাম 1, প্যারাম 2 একটি উদ্ধৃত পরম]
জেসগিলন

2
aparse() {
while [[ $# > 0 ]] ; do
  case "$1" in
    --arg1)
      varg1=${2}
      shift
      ;;
    --arg2)
      varg2=true
      ;;
  esac
  shift
done
}

aparse "$@"

1
নীচে যেমন বলা [ $# != 0 ]ভাল ভাল। উপরের হিসাবে , হিসাবে #$হতে হবে$#while [[ $# > 0 ]] ...
hute37

1

বাজের উত্তরে বিশদকরণ, আপনার যদি সূচকের সাথে যুক্তি তালিকাটি গণনা করার প্রয়োজন হয় (যেমন একটি নির্দিষ্ট শব্দের সন্ধান করা), আপনি তালিকাটি অনুলিপি বা পরিবর্তন না করে এটি করতে পারেন this

বলুন যে আপনি একটি আর্গুমেন্টের তালিকাটি ডাবল-ড্যাশ ("-") এ বিভক্ত করতে চান এবং ড্যাশগুলির আগে একটি কমান্ডের কাছে যুক্তিগুলি এবং অন্যটি ড্যাশের পরে যুক্তিগুলি প্রেরণ করতে চান:

 toolwrapper() {
   for i in $(seq 1 $#); do
     [[ "${!i}" == "--" ]] && break
   done || return $? # returns error status if we don't "break"

   echo "dashes at $i"
   echo "Before dashes: ${@:1:i-1}"
   echo "After dashes: ${@:i+1:$#}"
 }

ফলাফলগুলি এর মতো দেখতে হবে:

 $ toolwrapper args for first tool -- and these are for the second
 dashes at 5
 Before dashes: args for first tool
 After dashes: and these are for the second

1

getopt কোনও কমান্ড লাইন বিকল্প বা প্যারামিটার বিন্যাস করতে আপনার স্ক্রিপ্টগুলিতে কমান্ড ব্যবহার করুন।

#!/bin/bash
# Extract command line options & values with getopt
#
set -- $(getopt -q ab:cd "$@")
#
echo
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) param="$2"
echo "Found the -b option, with parameter value $param"
shift ;;
-c) echo "Found the -c option" ;;
--) shift
break ;;
*) echo "$1 is not an option";;
esac
shift

কৌতুকপূর্ণ, আমি এটি সম্পর্কে ভালভাবে গবেষণা করব। উদাহরণ: ফাইল: ///usr/share/doc/util-linux/example/getopt-parse.bash
জিমি ল্যান্ডস্টুডিওগুলি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.