আপনি কখন অতিরিক্ত ফাইল বর্ণনাকারী ব্যবহার করবেন?


74

আমি জানি আপনি একটি ফাইল বর্ণনাকারী তৈরি করতে এবং এতে আউটপুট পুনর্নির্দেশ করতে পারেন। যেমন

exec 3<> /tmp/foo # open fd 3.
echo a >&3 # write to it
exec 3>&- # close fd 3.

তবে আপনি ফাইল বর্ণনাকারী ব্যতীত একই জিনিসটি করতে পারেন:

FILE=/tmp/foo
echo a > "$FILE"

আমি আপনাকে একটি অতিরিক্ত ফাইল বর্ণনাকারী কখন ব্যবহার করতে হবে তার একটি ভাল উদাহরণ খুঁজছি।

উত্তর:


50

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

while IFS= read -r line; do
  printf '%s\n' "$line"
  if IFS= read -r line; then printf '%s\n' "$line" >&3; fi
done >odd.txt 3>even.txt

এখন ধরুন আপনি বিজোড় সংখ্যা লাইনগুলিতে এবং সমান সংখ্যাযুক্ত লাইনে একটি আলাদা ফিল্টার প্রয়োগ করতে চান (তবে এগুলি আবার একসাথে রাখবেন না, এটি একটি পৃথক সমস্যা হবে, সাধারণভাবে শেল থেকে সম্ভাব্য নয়)। শেলটিতে, আপনি কেবলমাত্র একটি কমান্ডের স্ট্যান্ডার্ড আউটপুটটিকে অন্য কমান্ডে পাইপ করতে পারেন; অন্য ফাইল বর্ণনাকারী পাইপ করতে, আপনাকে প্রথমে এফডি 1 এ পুনর্নির্দেশ করতে হবে।

{ while  done | odd-filter >filtered-odd.txt; } 3>&1 | even-filter >filtered-even.txt

আরেকটি, সরল ব্যবহারের ক্ষেত্রে একটি কমান্ডের ত্রুটি আউটপুট ফিল্টার করা হয়

exec M>&Nস্ক্রিপ্টের অবশিষ্ট অংশের জন্য ফাইলের বিবরণকারীকে অন্য একটিতে পুনর্নির্দেশ করে (বা অন্য কোনও কমান্ড ফাইলের বর্ণনাকারীদের আবার পরিবর্তন না করে)। exec M>&Nএবং এর মধ্যে কার্যকারিতাটিতে কিছু ওভারল্যাপ রয়েছে somecommand M>&Nexecআকারে এটি নেস্টেড করতে হবে না যে, বেশি শক্তিশালী:

exec 8<&0 9>&1
exec >output12
command1
exec <input23
command2
exec >&9
command3
exec <&8

অন্যান্য উদাহরণ যা আগ্রহী হতে পারে:

এবং আরও উদাহরণের জন্য:

পিএস এটি একটি বিস্ময়কর প্রশ্ন যা সাইটের এফডি 3 এর মাধ্যমে পুনর্নির্দেশ ব্যবহার করে এমন সাইটের সর্বাধিক উত্সাহিত পোস্টের লেখকের কাছ থেকে !


আমি বরং বলব যে "বেশিরভাগ কমান্ডের মধ্যে একক বা ডাবল আউটপুট চ্যানেল থাকে - স্টডআউট (এফডি 1) এবং প্রায়শই স্টেডার (এফডি 2)"।
rozcietrzewiacz

এছাড়াও, আপনি কীভাবে ব্যবহার করছেন তা ব্যাখ্যা করতে পারেন while IFS= read -r line;? আমি এটি যেভাবে দেখছি, আইএফএসের এখানে কোনও প্রভাব নেই কারণ আপনি কেবলমাত্র একটি ভেরিয়েবল ( লাইন ) এর মান নির্ধারণ করেন । এই প্রশ্নটি দেখুন।
rozcietrzewiacz

@ জর্জিট্রিজেভিয়াক্জ আমি স্টাডারের একটি উল্লেখ করেছি এবং আমার উত্তরের প্রথম অংশটি দেখুন কেন IFSআপনি একক ভেরিয়েবল (এটি শীর্ষস্থানীয় সাদা স্থানকে ধরে রাখার জন্য) পড়তে চাইলেও কেন পার্থক্য হয়।
গিলস

আপনি কি একই সাথে করতে পারেন না sed -ne 'w odd.txt' -e 'n;w even.txt'?
ওয়াইল্ডকার্ড

1
@ উইল্ডকার্ড আপনি অবশ্যই অন্যান্য সরঞ্জামগুলির সাথে একই কাজ করতে পারেন। তবে এই উত্তরের লক্ষ্যটি ছিল শেলের পুনর্নির্দেশগুলি চিত্রিত করা।
গিলস

13

বাশ স্ক্রিপ্ট চ্যাটিনেস নিয়ন্ত্রণ হিসাবে অতিরিক্ত এফডি ব্যবহার করার উদাহরণ এখানে:

#!/bin/bash

log() {
    echo $* >&3
}
info() {
    echo $* >&4
}
err() {
    echo $* >&2
}
debug() {
    echo $* >&5
}

VERBOSE=1

while [[ $# -gt 0 ]]; do
    ARG=$1
    shift
    case $ARG in
        "-vv")
            VERBOSE=3
        ;;
        "-v")
            VERBOSE=2
        ;;
        "-q")
            VERBOSE=0
        ;;
        # More flags
        *)
        echo -n
        # Linear args
        ;;
    esac
done

for i in 1 2 3; do
    fd=$(expr 2 + $i)
    if [[ $VERBOSE -ge $i ]]; then
        eval "exec $fd>&1"
    else
        eval "exec $fd> /dev/null"
    fi
done

err "This will _always_ show up."
log "This is normally displayed, but can be prevented with -q"
info "This will only show up if -v is passed"
debug "This will show up for -vv"

8

নামযুক্ত পাইপ (ফিফোস) প্রসঙ্গে অতিরিক্ত ফাইল বর্ণনাকারীর ব্যবহার নন-ব্লকিং পাইপিং আচরণ সক্ষম করতে পারে।

(
rm -f fifo
mkfifo fifo
exec 3<fifo   # open fifo for reading
trap "exit" 1 2 3 15
exec cat fifo | nl
) &
bpid=$!

(
exec 3>fifo  # open fifo for writing
trap "exit" 1 2 3 15
while true;
do
    echo "blah" > fifo
done
)
#kill -TERM $bpid

দেখুন: স্ক্রিপ্টে অকাল আগেই বন্ধ পাইপ নামকরণ?


1
আপনি আমার একটি পুরানো প্রশ্ন খনন করেছেন :) চাদ ঠিক আছে, আপনি একটি রেসের শর্তে চলে যাবেন।
n0pe

6

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

arg1 string to echo 
arg2 flag 0,1 print or not print to 3rd fd stdout descriptor   
function ecko3 {  
if [ "$2" -eq 1 ]; then 
    exec 3>$(tty) 
    echo -en "$1" | tee >(cat - >&3)
    exec 3>&- 
else 
    echo -en "$1"  
fi 
}

2
আমি জানি এটি কোনও নতুন উত্তর নয়, তবে এটি কী করে তা দেখার জন্য আমাকে এই মুহুর্তের দিকে তাকাতে হয়েছিল এবং ভেবেছিল যে কেউ যদি এই ফাংশনটি ব্যবহারের উদাহরণ যুক্ত করে তবে এটি সহায়ক হবে। এই একটি প্রতিধ্বনি এবং পুরো আউটপুট ক্যাপচার করে একটি কমান্ড - ডিএফ, এই ক্ষেত্রে। dl.rodboxusercontent.com/u/54584985/mytest_redirect
জো

3

অতিরিক্ত ফাইল বর্ণনাকারী ব্যবহার করার সময় যথাযথ বলে মনে হওয়ার পরে এখানে আরও একটি পরিস্থিতি রয়েছে (ব্যাশে):

কমান্ড-লাইন পরামিতিগুলির শেল স্ক্রিপ্ট পাসওয়ার্ড সুরক্ষা

env -i bash --norc   # clean up environment
set +o history
read -s -p "Enter your password: " passwd
exec 3<<<"$passwd"
mycommand <&3  # cat /dev/stdin in mycommand

1

উদাহরণ: ফাইল লক সহ সিরিয়ালি চালাতে স্ক্রিপ্টগুলিকে জোর করতে ঝাঁক ব্যবহার করা

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

#exit if any command returns a non-zero exit code (like flock when it fails to lock)
set -e

#open file descriptor 3 for writing
exec 3> /tmp/file.lock

#create an exclusive lock on the file using file descriptor 3
#exit if lock could not be obtained
flock -n 3

#execute serial code

#remove the file while the lock is still obtained
rm -f /tmp/file.lock

#close the open file handle which releases the file lock and disk space
exec 3>&-

লক এবং আনলক সংজ্ঞায়িত করে কার্যত পর্বত ব্যবহার করুন

আপনি এই লকিং / আনলকিং লজিকটিকে পুনরায় ব্যবহারযোগ্য ফাংশনে আবদ্ধ করতে পারেন। নিম্নলিখিত trapশেলটি অন্তর্নির্মিত স্ক্রিপ্টটি বের হয়ে গেলে স্বয়ংক্রিয়ভাবে ফাইল লক প্রকাশ করবে (ত্রুটি বা সাফল্য)। trapআপনার ফাইল লকগুলি পরিষ্কার করতে সহায়তা করে। পাথটি /tmp/file.lockএকটি শক্ত কোডড পথ হওয়া উচিত যাতে একাধিক স্ক্রিপ্ট এতে লক করার চেষ্টা করতে পারে।

# obtain a file lock and automatically unlock it when the script exits
function lock() {
  exec 3> /tmp/file.lock
  flock -n 3 && trap unlock EXIT
}

# release the file lock so another program can obtain the lock
function unlock() {
  # only delete if the file descriptor 3 is open
  if { >&3 ; } &> /dev/null; then
    rm -f /tmp/file.lock
  fi
  #close the file handle which releases the file lock
  exec 3>&-
}

unlockযুক্তিবিজ্ঞান উপরে সামনে লক মুক্তি হয় ফাইল মুছে ফেলতে হয়। এইভাবে এটি লক ফাইলটি পরিষ্কার করে। ফাইলটি মোছা হওয়ায় এই প্রোগ্রামের অন্য একটি উদাহরণ ফাইল লকটি অর্জন করতে সক্ষম।

স্ক্রিপ্টগুলিতে লক এবং আনলক ফাংশনগুলির ব্যবহার

আপনি নিম্নলিখিত স্ক্রিপ্টগুলিতে এটি ব্যবহার করতে পারেন।

#exit if any command returns a non-zero exit code (like flock when it fails to lock)
set -e

#try to lock (else exit because of non-zero exit code)
lock

#system-wide serial locked code

unlock

#non-serial code

আপনি যদি চান আপনার কোডটি এটি লক করতে সক্ষম না হওয়া পর্যন্ত অপেক্ষা করতে পারে তবে আপনি স্ক্রিপ্টটি এডজাস্ট করতে পারেন:

set -e

#wait for lock to be successfully obtained
while ! lock 2> /dev/null; do
  sleep .1
done

#system-wide serial locked code

unlock

#non-serial code

0

একটি দৃ concrete় উদাহরণ হিসাবে, আমি সবেমাত্র একটি স্ক্রিপ্ট লিখেছিলাম যার একটি সাবকমন্ডের সময়কালীন তথ্যের প্রয়োজন। অতিরিক্ত ফাইল ডেস্ক্রিপ্টর ব্যবহার timeকরে সাব কমান্ডের স্টাডাউট বা স্ট্ডারকে বাধা না দিয়েই কমান্ডের স্টডারার ক্যাপচারের অনুমতি দেয়।

(time ls -9 2>&3) 3>&2 2> time.txt

এটি যা করে তা হল পয়েন্টের lsস্টার্ডার থেকে এফডি 3, পয়েন্টের এফডি 3 স্ক্রিপ্টের স্টার্ডার এবং পয়েন্ট timeএর স্টার্ডার একটি ফাইলে। স্ক্রিপ্টটি যখন চালানো হয় তখন এর স্টাডআউট এবং স্ট্ডার সাবকম্যান্ডের মতো হয়, যা যথারীতি পুনঃনির্দেশ করা যায়। কেবলমাত্র timeআউটপুট ফাইলটিতে পুনর্নির্দেশ করা হয়।

$ echo '(time ls my-example-script.sh missing-file 2>&3) 3>&2 2> time.txt' > my-example-script.sh
$ chmod +x my-example-script.sh 
$ ./my-example-script.sh 
ls: missing-file: No such file or directory
my-example-script.sh
$ ./my-example-script.sh > /dev/null
ls: missing-file: No such file or directory
$ ./my-example-script.sh 2> /dev/null
my-example-script.sh
$ cat time.txt

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