বাশ: বেনামে ফিফো তৈরি করুন


38

আমরা সবাই জানি mkfifoএবং পাইপলাইনগুলি। প্রথমটি একটি নামযুক্ত পাইপ তৈরি করে , এইভাবে একটি নাম নির্বাচন করতে হয়, সম্ভবত এটির mktempলিঙ্কটি পরে থাকে এবং পরে মনে হয়। অন্যটি একটি বেনামে পাইপ তৈরি করে, নাম এবং অপসারণ নিয়ে কোনও ঝামেলা নেই, তবে পাইপের শেষ প্রান্তটি পাইপলাইনে কমান্ডের সাথে আবদ্ধ হয়, কোনওভাবেই ফাইল বর্ণনাকারীর আঁকড়ে ধরা এবং বাকীগুলিতে সেগুলি ব্যবহার করা সত্যই সুবিধাজনক নয় লিপি। সংকলিত প্রোগ্রামে, আমি কেবল করতাম ret=pipe(filedes); বাশ-এ বাশ-এর ​​মধ্যে exec 5<>fileএমন কিছু আশা করা যায় "exec 5<> -"বা "pipe <5 >6"-বাশের মতো কিছু আছে?

উত্তর:


42

বর্তমান নামক প্রক্রিয়াটি সংযুক্ত করার পরে আপনি কোনও নামযুক্ত পাইপটিকে আনলিংক করতে পারেন, যার ফলস্বরূপ কোনও বেনামে পাইপের ফলস্বরূপ:

# create a temporary named pipe
PIPE=$(mktemp -u)
mkfifo $PIPE
# attach it to file descriptor 3
exec 3<>$PIPE
# unlink the named pipe
rm $PIPE
...
# anything we write to fd 3 can be read back from it
echo 'Hello world!' >&3
head -n1 <&3
...
# close the file descriptor when we are finished (optional)
exec 3>&-

যদি আপনি প্রকৃতপক্ষে নামযুক্ত পাইপগুলি এড়াতে চান (যেমন ফাইল সিস্টেমটি কেবল পঠনযোগ্য) তবে আপনার "ফাইল বর্ণনাকারীর একটি গ্রিপ পান" ধারণাটিও কার্যকর হয়। মনে রাখবেন যে প্রোফস ব্যবহারের কারণে এটি লিনাক্স-নির্দিষ্ট।

# start a background pipeline with two processes running forever
tail -f /dev/null | tail -f /dev/null &
# save the process ids
PID2=$!
PID1=$(jobs -p %+)
# hijack the pipe's file descriptors using procfs
exec 3>/proc/$PID1/fd/1 4</proc/$PID2/fd/0
# kill the background processes we no longer need
# (using disown suppresses the 'Terminated' message)
disown $PID2
kill $PID1 $PID2
...
# anything we write to fd 3 can be read back from fd 4
echo 'Hello world!' >&3
head -n1 <&4
...
# close the file descriptors when we are finished (optional)
exec 3>&- 4<&-

: আপনি অব্যবহৃত ফাইল বর্ণনাকারী স্বয়ংক্রিয় গবেষনার সঙ্গে এই একত্রিত করতে পারেন stackoverflow.com/questions/8297415/...
CMCDragonkai

23

যদিও আমি জানি শেলগুলির কোনওটিই কাঁটাচামচ ছাড়া পাইপ তৈরি করতে পারে না, কিছুতে বেসিক শেল পাইপলাইনের চেয়ে ভাল।

আপনার সিস্টেমটি সমর্থন করে /dev/fd(বেশিরভাগ সময় আজকাল করুন) ধরে ধরে বাশ, কেএসএল এবং জেডএসে, আপনি কোনও কমান্ডের ইনপুট বা আউটপুট কোনও ফাইলের সাথে টাই করতে পারেন: <(command)একটি ফাইলের নামের সাথে প্রসারিত হয় যা আউটপুটটির সাথে সংযুক্ত পাইপকে ডিজাইন করে command, এবং >(command)প্রসারিত করে ফাইলের নামের সাথে যা ইনপুটটির সাথে সংযুক্ত পাইপকে ডিজাইন করে command। এই বৈশিষ্ট্যটিকে প্রক্রিয়া প্রতিস্থাপন বলা হয় । এর প্রাথমিক উদ্দেশ্যটি হ'ল একাধিক কমান্ডের অন্যের মধ্যে বা বাইরে পাইপ করা, যেমন,

diff <(transform <file1) <(transform <file2)
tee >(transform1 >out1) >(transform2 >out2)

এটি বেসিক শেল পাইপের কিছু ত্রুটিগুলি মোকাবেলায় দরকারী। উদাহরণস্বরূপ, এটির command2 < <(command1)সমতুল্য command1 | command2, তার স্থিতিটি বাদে command2। আর একটি ব্যবহারের কেসটি হ'ল exec > >(postprocessing)এটি সম্পূর্ণরূপে স্ক্রিপ্টের পুরো অংশটি ভিতরে রাখার চেয়ে সমান, তবে তার চেয়ে বেশি পঠনযোগ্য { ... } | postprocessing


আমি এটি ভিন্নতার সাথে চেষ্টা করেছি এবং এটি কাজ করেছে তবে কেডিফ 3 বা ইমাস দিয়ে, এটি কার্যকর হয়নি। আমার অনুমান যে kdiff3 পড়ার আগে অস্থায়ী / দেব / এফডি ফাইলটি সরানো হচ্ছে। অথবা সম্ভবত কেডিফ 3 ফাইলটি দু'বার পড়ার চেষ্টা করছে এবং পাইপটি কেবল একবার পাঠাচ্ছে?
ইয়াল

@ আইয়াল প্রক্রিয়া সহ্য করার সাথে ফাইলটির নাম হ'ল "যাদু" একটি পাইপের রেফারেন্স (বা ইউনিক্স ভেরিয়েন্টের একটি অস্থায়ী ফাইল যা এই যাদু রূপগুলিকে সমর্থন করে না)। জাদু কীভাবে প্রয়োগ করা হয় তা ওএসের উপর নির্ভর করে। লিনাক্স তাদের "যাদু" প্রতীকী লিঙ্ক হিসাবে প্রয়োগ করে যার লক্ষ্যটি কোনও বৈধ ফাইলের নাম নয় (এটি এমন কিছু pipe:[123456])। ইমাকস দেখেছে যে সিমলিংকের লক্ষ্যটি কোনও বিদ্যমান ফাইলের নাম নয় এবং এটি যথেষ্ট পরিমাণে বিভ্রান্ত করে যে এটি ফাইলটি পড়ে না (এটি কোনওভাবেই এটি পড়তে পারে এমন একটি বিকল্প থাকতে পারে, যদিও ইমাকগুলি পাইপ খোলার মতো পছন্দ করে না যাইহোক ফাইল)।
গিলস 'অশুভ হওয়া বন্ধ করুন'

10

বাশ 4 এর কপোরাসেস রয়েছে

একটি কোপ্রোসেস একটি সাবসেল-এ অবিচ্ছিন্নভাবে সম্পাদন করা হয়, যেন কমান্ডটি '&' কন্ট্রোল অপারেটরের সাথে শেষ হয়ে গেছে, এক্সিকিউটিভ শেল এবং কোপ্রোসেসের মধ্যে দ্বি-দ্বীপ পাইপ স্থাপন করা হয়েছিল।

কোনও কપ્રোসেসের জন্য ফর্ম্যাটটি হ'ল:

coproc [NAME] command [redirections] 

3

অক্টোবর ২০১২ পর্যন্ত এই কার্যকারিতাটি এখনও বাশের মধ্যে বিদ্যমান বলে মনে হচ্ছে না, তবে কপোক্রোক ব্যবহার করা যেতে পারে যদি আপনার নামবিহীন / বেনামে পাইপগুলির দরকার হয় তবে একটি শিশু প্রক্রিয়াতে কথা বলা। এই মুহুর্তে কপোক্রোকের সমস্যাটি হ'ল আপাতদৃষ্টিতে কেবল একবারে সমর্থিত। কপোক্রোক কেন এই সীমাবদ্ধতা পেয়েছিল তা আমি বুঝতে পারি না। এগুলি বিদ্যমান টাস্ক ব্যাকগ্রাউন্ডিং কোডের উন্নত হওয়া উচিত (ও & ও), তবে এটি বাশের লেখকদের জন্য একটি প্রশ্ন।


কেবল একটি কপ্রোসেসই সমর্থিত নয়। আপনি তাদের নাম রাখতে পারেন, যতক্ষণ না আপনি কোনও সহজ আদেশ প্রদান করেন না name পরিবর্তে এটিকে একটি কমান্ডের তালিকা দিন: coproc THING { dothing; }এখন আপনার এফডি রয়েছে ${THING[*]}এবং আপনি coproc OTHERTHING { dothing; }উভয়কেই চালাতে এবং প্রেরণ করতে এবং গ্রহণ করতে পারেন ।
ক্লেক

2
BUGS man bashশিরোনামের অধীনে @ ক্ল্যাক ইন , তারা এটি বলে: এক সময়ে কেবলমাত্র একটিমাত্র সক্রিয় কপ্রোসেস থাকতে পারে । আপনি যদি দ্বিতীয় কপোক্রোক শুরু করেন তবে আপনি একটি সতর্কতা পাবেন। এটি কাজ করে বলে মনে হচ্ছে তবে পটভূমিতে কী বিস্ফোরিত হয় তা আমি জানি না।
রাদু সি

ঠিক আছে, সুতরাং এটি বর্তমানে ভাগ্য দ্বারা কাজ করে, কারণ এটি উদ্দেশ্যমূলক ছিল না। পরিষ্কার সতর্কতা, ধন্যবাদ। :-)
ক্লেক

2

@ ডেভিডএন্ডারসনের উত্তরটি সমস্ত ঘাঁটিগুলি জুড়ে এবং কিছু দুর্দান্ত সুরক্ষার প্রস্তাব দেয়, তবে এটির সবচেয়ে গুরুত্বপূর্ণ বিষয়টি যা প্রকাশ করে তা হ'ল <(:)যতক্ষণ আপনি লিনাক্সে থাকবেন ততক্ষণ কোনও বেনামে পাইপে হাত দেওয়া সহজ is

সুতরাং আপনার প্রশ্নের সংক্ষিপ্ত এবং সহজ উত্তর হ'ল:

exec 5<> <(:)

ম্যাকোজে এটি কাজ করবে না, তারপরে আপনার নাম ফিফোর না করা পর্যন্ত আপনাকে অস্থায়ী ডিরেক্টরি তৈরি করতে হবে। আমি অন্যান্য বিএসডি সম্পর্কে জানি না।


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

@ ডেভিডএন্ডারসন আপনার মতামতটি আমার থেকে এই বিষয়ে আরও গভীর জ্ঞান আছে। লিনাক্স আচরণটি একটি বাগ কেন?
ক্লেক

1
যদি execপাস হয়ে যায় এবং বেনামে ফিফো যা কেবল পড়ার জন্য খোলা থাকে, তবে execএই বেনামে ফিফোর কোনও কাস্টম ফাইল বিবরণকারী ব্যবহার করে পড়ার জন্য এবং লেখার জন্য খোলার অনুমতি দেওয়া উচিত নয়। আপনার কাছে কোনও -bash: /dev/fd/5: Permission deniedবার্তা পাওয়ার আশা করা উচিত , যা ম্যাকোস ইস্যু করে। আমি বিশ্বাস করি যে বাগটি হ'ল উবুন্টু একই বার্তা দেয় না। যদি কেউ ডকুমেন্টেশন exec 5<> <(:)প্রযোজনীয় অনুমোদিত বলে প্রযোজনা করতে পারে তবে আমি আমার মন পরিবর্তন করতে ইচ্ছুক ।
ডেভিড অ্যান্ডারসন

@ ডেভিড অ্যান্ডারসন বাহ, এটি আকর্ষণীয়। আমি ধরে নিয়েছি বাশ অভ্যন্তরীণভাবে কিছু করছে, তবে এটি সক্রিয় হয়ে গেছে যে এটি লিনাক্সের open(..., O_RDWR)পরিবর্তে প্রতিস্থাপনের দ্বারা সরবরাহ করা এক দিকনির্দেশক পাইপ প্রান্তে করার অনুমতি দেয় এবং এটি এটিকে একটি এফডি-তে দ্বি-নির্দেশমূলক পাইপে পরিণত করে। আপনি সম্ভবত সঠিক যে কেউ এই উপর নির্ভর করা উচিত নয়। :-D পাইপ তৈরি করতে এক্সিলিনের পাইপারউ ব্যবহার করে আউটপুট , তারপরে এটি ব্যাশ দিয়ে পুনর্নির্মাণ করুন<> : libranet.de/display/0b6b25a8-195c-84af-6ac7-ee6696661765
ক্লেক

এটি যে গুরুত্বপূর্ণ তা নয়, তবে আপনি যদি উবুন্টুর নীচে দেখতে চান exec 5<>তবে কী লিখুন fun() { ls -l $1; ls -lH $1; }; fun <(:)
ডেভিড অ্যান্ডারসন

1

নিম্নলিখিত ফাংশনটি ব্যবহার করে পরীক্ষা করা হয়েছিল GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)। অপারেটিং সিস্টেমটি ছিল উবুন্টু 18 This এই ফাংশনটিতে একটি একক প্যারামিটার লাগে যা বেনামে ফিফোর জন্য পছন্দসই ফাইল বর্ণনাকারী।

MakeFIFO() {
    local "MakeFIFO_upper=$(ulimit -n)" 
    if [[ $# -ne 1 || ${#1} -gt ${#MakeFIFO_upper} || -n ${1%%[0-9]*} || 10#$1 -le 2
        || 10#$1 -ge MakeFIFO_upper ]] || eval ! exec "$1<> " <(:) 2>"/dev/null"; then
        echo "$FUNCNAME: $1: Could not create FIFO" >&2
        return "1"
    fi
}

নিম্নলিখিত ফাংশনটি ব্যবহার করে পরীক্ষা করা হয়েছিল GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)। অপারেটিং সিস্টেমটি ছিল ম্যাকওএস হাই সিয়েরা। এই ফাংশনটি কেবলমাত্র তৈরি করা প্রক্রিয়াটির জন্য পরিচিত একটি অস্থায়ী ডিরেক্টরিতে একটি নামী ফিফো তৈরি করে শুরু হয় । এরপরে, ফাইল বর্ণনাকারী ফিফোর কাছে পুনঃনির্দেশিত হয়। অবশেষে, অস্থায়ী ডিরেক্টরিটি মোছার মাধ্যমে ফিফোর ফাইল নাম থেকে লিঙ্কমুক্ত করা হয়। এটি ফিফোর বেনামে পরিণত করে।

MakeFIFO() {
    MakeFIFO.SetStatus() {
        return "${1:-$?}"
    }
    MakeFIFO.CleanUp() {
        local "MakeFIFO_status=$?"
        rm -rf "${MakeFIFO_directory:-}"    
        unset "MakeFIFO_directory"
        MakeFIFO.SetStatus "$MakeFIFO_status" && true
        eval eval "${MakeFIFO_handler:-:}'; true'" 
    }
    local "MakeFIFO_success=false" "MakeFIFO_upper=$(ulimit -n)" "MakeFIFO_file=" 
    MakeFIFO_handler="$(trap -p EXIT)"
    MakeFIFO_handler="${MakeFIFO_handler#trap -- }"
    MakeFIFO_handler="${MakeFIFO_handler% *}"
    trap -- 'MakeFIFO.CleanUp' EXIT
    until "$MakeFIFO_success"; do
        [[ $# -eq 1 && ${#1} -le ${#MakeFIFO_upper} && -z ${1%%[0-9]*}
        && 10#$1 -gt 2 && 10#$1 -lt MakeFIFO_upper ]] || break
        MakeFIFO_directory=$(mktemp -d) 2>"/dev/null" || break
        MakeFIFO_file="$MakeFIFO_directory/pipe"
        mkfifo -m 600 $MakeFIFO_file 2>"/dev/null" || break
        ! eval ! exec "$1<> $MakeFIFO_file" 2>"/dev/null" || break
        MakeFIFO_success="true"
    done
    rm -rf "${MakeFIFO_directory:-}"
    unset  "MakeFIFO_directory"
    eval trap -- "$MakeFIFO_handler" EXIT
    unset  "MakeFIFO_handler"
    "$MakeFIFO_success" || { echo "$FUNCNAME: $1: Could not create FIFO" >&2; return "1"; }
}

উপরের ফাংশনগুলি একটি একক ফাংশনে একত্রিত হতে পারে যা উভয় অপারেটিং সিস্টেমে কাজ করবে। নীচে যেমন একটি ফাংশন উদাহরণ। এখানে, সত্যিকার অর্থে একটি বেনামে ফিফো তৈরির চেষ্টা করা হয়েছে। যদি ব্যর্থ হয়, তবে একটি নামী ফিফো তৈরি করা হবে এবং একটি বেনামে ফিফায় রূপান্তর করা হবে।

MakeFIFO() {
    MakeFIFO.SetStatus() {
        return "${1:-$?}"
    }
    MakeFIFO.CleanUp() {
        local "MakeFIFO_status=$?"
        rm -rf "${MakeFIFO_directory:-}"    
        unset "MakeFIFO_directory"
        MakeFIFO.SetStatus "$MakeFIFO_status" && true
        eval eval "${MakeFIFO_handler:-:}'; true'" 
    }
    local "MakeFIFO_success=false" "MakeFIFO_upper=$(ulimit -n)" "MakeFIFO_file=" 
    MakeFIFO_handler="$(trap -p EXIT)"
    MakeFIFO_handler="${MakeFIFO_handler#trap -- }"
    MakeFIFO_handler="${MakeFIFO_handler% *}"
    trap -- 'MakeFIFO.CleanUp' EXIT
    until "$MakeFIFO_success"; do
        [[ $# -eq 1 && ${#1} -le ${#MakeFIFO_upper} && -z ${1%%[0-9]*}
        && 10#$1 -gt 2 && 10#$1 -lt MakeFIFO_upper ]] || break
        if eval ! exec "$1<> " <(:) 2>"/dev/null"; then
            MakeFIFO_directory=$(mktemp -d) 2>"/dev/null" || break
            MakeFIFO_file="$MakeFIFO_directory/pipe"
            mkfifo -m 600 $MakeFIFO_file 2>"/dev/null" || break
            ! eval ! exec "$1<> $MakeFIFO_file" 2>"/dev/null" || break
        fi
        MakeFIFO_success="true"
    done
    rm -rf "${MakeFIFO_directory:-}"
    unset  "MakeFIFO_directory"
    eval trap -- "$MakeFIFO_handler" EXIT
    unset  "MakeFIFO_handler"
    "$MakeFIFO_success" || { echo "$FUNCNAME: $1: Could not create FIFO" >&2; return "1"; }
}

এখানে বেনামে ফিফো তৈরির উদাহরণ রয়েছে, তারপরে একই ফিফোতে কিছু পাঠ্য লেখা।

fd="6"
MakeFIFO "$fd"
echo "Now is the" >&"$fd"
echo "time for all" >&"$fd"
echo "good men" >&"$fd"

বেনামে ফিফোর সম্পূর্ণ বিষয়বস্তু পড়ার উদাহরণ নীচে দেওয়া হয়েছে।

echo "EOF" >&"$fd"
while read -u "$fd" message; do
    [[ $message != *EOF ]] || break
    echo "$message"
done

এটি নিম্নলিখিত আউটপুট উত্পাদন করে।

Now is the
time for all
good men

নীচের কমান্ডটি বেনামে ফিফো বন্ধ করে দেয়।

eval exec "$fd>&-"

তথ্যসূত্র:
পরে ব্যবহারের জন্য বেনামে পাইপ তৈরি করা
জনসাধারণের জন্য লিখিতযোগ্য ডিরেক্টরিতে ফাইলগুলি বিপজ্জনক
শেল স্ক্রিপ্ট সুরক্ষা


0

এইচটিএমএর দুর্দান্ত এবং উজ্জ্বল উত্তরটি ব্যবহার করে, আমি এটি একটি লাইনারে এটি ব্যবহার করতে কিছুটা সংশোধন করেছি, এটি এখানে:

# create a temporary named pipe
PIPE=(`(exec 0</dev/null 1</dev/null; (( read -d \  e < /proc/self/stat ; echo $e >&2 ; exec tail -f /dev/null 2> /dev/null ) | ( read -d \  e < /proc/self/stat ; echo $e  >&2 ; exec tail -f /dev/null 2> /dev/null )) &) 2>&1 | for ((i=0; i<2; i++)); do read e; printf "$e "; done`)
# attach it to file descriptors 3 and 4
exec 3>/proc/${PIPE[0]}/fd/1 4</proc/${PIPE[1]}/fd/0
...
# kill the temporary pids
kill ${PIPE[@]}
...
# anything we write to fd 3 can be read back from fd 4
echo 'Hello world!' >&3
head -n1 <&4
...
# close the file descriptor when we are finished (optional)
exec 3>&- 4<&-

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