শেলটি কোন ক্রমে আদেশগুলি এবং স্ট্রিম পুনঃনির্দেশকে কার্যকর করে?


32

আমি উভয় পুনর্নির্দেশ করতে চেষ্টা ছিল stdoutএবং stderrএকটি ফাইলে আজ, এবং আমি এই জুড়ে এসেছিল:

<command> > file.txt 2>&1

এটি দৃশ্যত প্রথমে পুনঃনির্দেশ stderrকরে stdoutএবং তারপরে ফলাফলটি stdoutপুনঃনির্দেশিত হয় file.txt

তবে, আদেশ কেন নয় <command> 2>&1 > file.txt? এটি স্বাভাবিকভাবেই পড়তে হবে (কমান্ডটি প্রথমে কার্যকর করা হচ্ছে, বাম থেকে ডানে ধরে মৃত্যুদন্ড ধরে নিয়ে যাওয়া), এরপরে stderrপুনঃনির্দেশিত করা হবে stdoutএবং তারপরে ফলাফলটি stdoutলিখিত হবে file.txt। তবে উপরেরগুলি কেবল stderrপর্দায় পুনর্নির্দেশ করে।

শেল কীভাবে উভয় আদেশকে ব্যাখ্যা করে?


7
টিএলসিএল বলেছেন এটি "প্রথমে আমরা স্ট্যান্ডার্ড আউটপুটটিকে ফাইলে পুনর্নির্দেশ করি এবং তারপরে আমরা ফাইল বর্ণনাকারী 2 (স্ট্যান্ডার্ড ত্রুটি) কে ডেস্ক্রিপ্টর ওয়ান (স্ট্যান্ডার্ড আউটপুট) ফাইল করতে" এবং "লক্ষ্য করুন যে পুনঃনির্দেশগুলির ক্রমটি উল্লেখযোগ্য standard স্ট্যান্ডার্ড ত্রুটির পুনঃনির্দেশ স্ট্যান্ডার্ড আউটপুট পুনঃনির্দেশের পরে সর্বদা অবশ্যই ঘটতে হবে বা এটি কাজ করে না "
Zanna

@ জান্না: হ্যাঁ, আমার প্রশ্নটি টিএলসিএল-তে পড়ে স্পষ্টভাবে এসেছে! :) কেন এটি কাজ করবে না, তা জানতে আগ্রহী, অর্থাত্ শেল কীভাবে সাধারণভাবে আদেশগুলি ব্যাখ্যা করে।
ট্রেন হার্টনেট

ঠিক আছে, আপনার প্রশ্নে আপনি বিপরীতটি বলেছেন "এটি স্পষ্টতই স্ট্যাডারকে প্রথমে স্টডআউটকে পুনঃনির্দেশ করে ..." - আমি টিএলসিএল থেকে যা বুঝতে পেরেছি তা হ'ল শেলটি স্টাডআউটকে ফাইলে প্রেরণ করে এবং তারপরে স্টার্ডারকে স্ট্যাডআউট (অর্থাত্ ফাইলটিতে) প্রেরণ করে । আমার ব্যাখ্যাটি হ'ল আপনি যদি স্ট্ডারকে স্টাডাউটে প্রেরণ করেন তবে এটি টার্মিনালে প্রদর্শিত হবে এবং পরবর্তী সময়ে স্টাডাউটের পুনঃনির্দেশ স্টেডারকে অন্তর্ভুক্ত করবে না (অর্থাত্ পর্দার স্ট্যাডারের পুনঃনির্দেশটি স্টাডাউটের পুনঃনির্দেশ ঘটানোর আগেই সম্পূর্ণ হয়?)
জান্না

7
আমি জানি এটি বলার মতো পুরানো কালের জিনিস, তবে আপনার শেলটি একটি ম্যানুয়াল নিয়ে আসে যা এই বিষয়গুলি ব্যাখ্যা করে - যেমন ম্যানুয়ালটিতে পুনঃনির্দেশbash । যাইহোক, পুনর্নির্দেশগুলি আদেশ নয়।
পোস্ট

কমান্ড না পারেন, পুনঃনির্দেশগুলি স্থাপন করা হয়েছে আগে কার্যকর করা: যখন execv-family প্রাপ্ত syscall আসলে কমান্ড বন্ধ subprocess হাতে বরকত হয় শুরু হচ্ছে, শেল তারপর লুপ (বাইরে আর যে প্রক্রিয়ায় নির্বাহ কোড আছে ) এবং সেই দিক থেকে যা ঘটে তা নিয়ন্ত্রণ করার কোনও সম্ভাব্য উপায় নেই; পুনর্নির্দেশগুলি কার্যকরভাবে সম্পাদন শুরুর আগে অবশ্যই সম্পাদন করা আবশ্যক , যখন শেলটি নিজেই fork()আপনার কমান্ডটি চালানোর জন্য সম্পাদিত প্রক্রিয়াটিতে চলছে তার একটি অনুলিপি রয়েছে
চার্লস ডফি

উত্তর:


41

আপনি যখন <command> 2>&1 > file.txtস্টার্ডার চালান যখন 2>&1স্টাডাউট বর্তমানে যায় তার দ্বারা পুনঃনির্দেশিত হয় , আপনার টার্মিনাল। এর পরে, স্টডআউট দ্বারা ফাইলটিতে পুনঃনির্দেশ করা হয় >, তবে স্ট্ডার এটির সাথে পুনঃনির্দেশিত হয় না, তাই টার্মিনাল আউটপুট হিসাবে থাকে।

সঙ্গে <command> > file.txt 2>&1stdout- এ প্রথম দ্বারা ফাইল থেকে আপনাকে পুনঃনির্দেশিত করা হয় >, তারপর 2>&1পুনঃনির্দেশ যেখানে stdout- এ যাচ্ছে, যা ফাইল থেকে stderr।

এটি দিয়ে শুরু করা স্বতঃস্ফূর্ত মনে হতে পারে তবে আপনি যখন পুনঃনির্দেশগুলি এইভাবে ভাবেন এবং মনে রাখবেন যে এগুলি বাম থেকে ডানে প্রক্রিয়া করা হয় তখন এটি আরও বেশি অর্থবোধ করে।


এটা জ্ঞান করে তোলে যদি আপনি ফাইল-বর্ণনাকারী পরিপ্রেক্ষিতে মনে এবং "DUP / fdreopen" কল থেকে অনুক্রমে মৃত্যুদন্ড কার্যকর করা হচ্ছে বাম-থেকে-ডান
মার্ক কে কাওয়ান

20

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

শুরুতে, stderr এবং stdout একই জিনিস (সাধারণত টার্মিনাল, আমি এখানে কল pts):

fd/0 -> pts
fd/1 -> pts
fd/2 -> pts

আমি এখানে তাদের ফাইল বর্ণনাকারী সংখ্যার সাহায্যে stdin, stdout এবং stderr উল্লেখ করছি : তারা যথাক্রমে 0, 1 এবং 2 ফাইল বর্ণনাকারী।

পুনর্নির্দেশের প্রথম সেটটিতে এখন আমাদের রয়েছে > file.txtএবং 2>&1

তাই:

  1. > file.txt: fd/1এখন যায় file.txt। সঙ্গে >, 1উহ্য ফাইল বর্ণনাকারী যখন কিছুই উল্লেখ করা হয়, তাই এই হল 1>file.txt:

    fd/0 -> pts
    fd/1 -> file.txt
    fd/2 -> pts
  2. 2>&1: fd/2এখন যেখানেই যায় fd/1 বর্তমানে যায়:

    fd/0 -> pts
    fd/1 -> file.txt
    fd/2 -> file.txt

অন্যদিকে, সাথে 2>&1 > file.txt, ক্রমটি বিপরীত হচ্ছে:

  1. 2>&1: বর্তমানে বর্তমানে fd/2যেখানেই fd/1যায় সেখানে অর্থাত্ কোনও পরিবর্তন হয় না:

    fd/0 -> pts
    fd/1 -> pts
    fd/2 -> pts
  2. > file.txt: fd/1এখন যায় file.txt:

    fd/0 -> pts
    fd/1 -> file.txt
    fd/2 -> pts

গুরুত্বপূর্ণ বিষয়টি হ'ল পুনঃনির্দেশের অর্থ এই নয় যে পুনঃনির্দেশিত ফাইল বর্ণনাকারী লক্ষ্য ফাইল বর্ণনাকারীর ভবিষ্যতের সমস্ত পরিবর্তনগুলি অনুসরণ করবে; এটি কেবলমাত্র বর্তমান অবস্থাতেই গ্রহণ করবে ।


আপনাকে ধন্যবাদ, এটি আরও প্রাকৃতিক ব্যাখ্যা বলে মনে হচ্ছে! :) আপনি 2.দ্বিতীয় অংশে কিছুটা হলেও টাইপ করেছেন ; fd/1 -> file.txtএবং না fd/2 -> file.txt
ট্রেন হার্টনেট

11

আমি মনে করি এটি ভাবতে সাহায্য করে যে শেলটি প্রথমে বামদিকে পুনঃনির্দেশটি সেট আপ করবে এবং পরবর্তী পুনঃনির্দেশটি সেট আপ করার আগে এটি সম্পূর্ণ করবে।

উইলিয়াম শটস এর লিনাক্স কমান্ড লাইন বলেছে

প্রথমে আমরা স্ট্যান্ডার্ড আউটপুটটিকে ফাইলে পুনর্নির্দেশ করি এবং তারপরে আমরা ফাইল বর্ণনাকারী 2 (স্ট্যান্ডার্ড ত্রুটি) ডেস্ক্রিপ্টর ওয়ান (স্ট্যান্ডার্ড আউটপুট) ফাইলের জন্য পুনর্নির্দেশ করি

এটি বোঝা যায়, কিন্তু তারপর

লক্ষ্য করুন যে পুনর্নির্দেশগুলির ক্রমটি উল্লেখযোগ্য। স্ট্যান্ডার্ড ত্রুটির পুনর্নির্দেশটি সর্বদা স্ট্যান্ডার্ড আউটপুট পুনর্নির্দেশের পরে অবশ্যই ঘটে থাকে বা এটি কাজ করে না

কিন্তু বাস্তবে, আমরা স্ট্ডারকে একই প্রভাবের সাথে একটি ফাইলে পুনর্নির্দেশের পরে স্টডারকে পুনঃনির্দেশ করতে পারি

$ uname -r 2>/dev/null 1>&2
$ 

সুতরাং, command > file 2>&1শেলটি একটি ফাইলে stdout প্রেরণ করে, তারপরে stdrr stdout এ প্রেরণ করে (যা কোনও ফাইলে প্রেরণ করা হচ্ছে)। যেহেতু, মধ্যে command 2>&1 > fileশেল প্রথম পুনঃনির্দেশ stdout- এ পরে stderr (অর্থাত প্রদর্শন এটা টার্মিনাল যেখানে stdout- এ স্বাভাবিকভাবে যায়) এবং তারপর, পুনঃনির্দেশ ফাইল stdout- এ। টিএলসিএল বিভ্রান্ত করছে যে আমাদের প্রথমে স্টডআউটকে পুনঃনির্দেশিত করতে হবে: যেহেতু আমরা স্টাডারকে প্রথমে একটি ফাইলে পুনর্নির্দেশ করতে পারি এবং তারপরে এটি স্টাডআউট প্রেরণ করতে পারি। আমরা যা করতে পারি না তা হ'ল স্টডআউটকে স্টার্ডারে পুনঃনির্দেশিত করা বা কোনও ফাইলে পুনর্নির্দেশের আগে তদ্বিপরীত । আরেকটি উদাহরণ

$ strace uname -r 1>&2 2> /dev/null 
4.8.0-30-generic

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

আমি আশা করি এটি কিছুটা আলো এনেছে ...


এত বেশি স্পষ্ট!
অ্যারোনিকাল

আহ, এখন বুঝি! আপনাকে অনেক ধন্যবাদ, @ জাঙ্কা এবং @ অ্যারোনিকাল! শুধু আমার কমান্ড লাইন যাত্রা শুরু। :)
ট্রেন হার্টনেট

@ ট্রেইন হার্টনেট এটি একটি আনন্দের! আশা করি আপনি আমার মতো এটি উপভোগ করছেন: ডি
জান্না

@ জান্না: আসলেই আমি! : ডি
ট্রেন হার্টনেট

2
@ ট্রেনহিয়ারনেট কোনও উদ্বেগ নয়, হতাশা এবং আনন্দের একটি পৃথিবী আপনার জন্য অপেক্ষা করছে!
অ্যারোনিকাল

10

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

পটভূমি: ফাইল বর্ণনাকারী বনাম ফাইল সারণী

আপনার ফাইল বর্ণনাকারী কেবল 0 ... এন, যা আপনার প্রক্রিয়াতে ফাইল বর্ণনাকারী সারণীতে সূচক। কনভেনশন অনুসারে, STDIN = 0, STDOUT = 1, STDERR = 2 (দ্রষ্টব্য যে এখানে শর্তাদি STDINকিছু প্রোগ্রামিং ভাষা এবং ম্যান পৃষ্ঠাতে কনভেনশন দ্বারা ব্যবহৃত প্রতীক / ম্যাক্রোগুলি, এখানে STDIN নামে একটি আসল "অবজেক্ট" নেই; এই আলোচনার উদ্দেশ্য, stdin হল 0, ইত্যাদি)।

এই ফাইল বর্ণনাকারী টেবিলটিতে প্রকৃত ফাইলটি সম্পর্কে কোনও তথ্য নেই। পরিবর্তে, এটিতে একটি পৃথক ফাইল টেবিলের পয়েন্টার রয়েছে; পরবর্তীকালে একটি প্রকৃত শারীরিক ফাইল (বা ব্লক ডিভাইস, বা পাইপ, বা লিনাক্স ফাইল মেকানিজমের মাধ্যমে সম্বোধন করতে পারে) এবং আরও তথ্য (যেমন এটি পড়া বা লেখার জন্য কিনা) সম্পর্কিত তথ্য রয়েছে।

সুতরাং আপনি যখন ব্যবহার করেন >বা <আপনার শেল ব্যবহার করেন , তখন আপনি কেবল অন্য কোনও দিকে নির্দেশ করতে সংশ্লিষ্ট ফাইল বর্ণনাকারীর পয়েন্টারটি প্রতিস্থাপন করেন। বাক্য গঠনটি 2>&1কেবল বর্ণনাকারী 2 কে যেখানে 1 পয়েন্টে নির্দেশ করে। > file.txtকেবল file.txtলেখার জন্য খোলে এবং স্টডআউট (ফাইল ডিক্স্রিপ্টর 1) এটিতে নির্দেশ করে।

অন্যান্য গুডিও রয়েছে, যেমন 2>(xxx) (যেমন: একটি নতুন প্রক্রিয়া চলমান xxxতৈরি করুন, একটি পাইপ তৈরি করুন, নতুন প্রক্রিয়াটির ফাইল বর্ণনাকারী 0 টি পাইপের পড়ার শেষের সাথে সংযুক্ত করুন এবং মূল প্রক্রিয়াটির 2 বর্ণনাকারী ফাইলটি লেখার শেষের সাথে সংযুক্ত করুন পাইপ)।

এটি আপনার শেল ছাড়াও অন্যান্য সফ্টওয়্যারের "ফাইল হ্যান্ডেল যাদু" এর ভিত্তি। উদাহরণস্বরূপ, আপনি, পার্ল স্ক্রিপ্টে, dupSTDOUT ফাইল বর্ণনাকারীকে অন্য (অস্থায়ী) একটিতে লাইসেন্স দিতে পারেন, তারপরে নতুন তৈরি হওয়া অস্থায়ী ফাইলটিতে STDOUT পুনরায় খুলতে পারেন। এই বিন্দু থেকে, আপনার নিজের পার্ল স্ক্রিপ্ট থেকে সমস্ত STDOUT আউটপুট এবংsystem() সেই স্ক্রিপ্টের সমস্ত কল সেই অস্থায়ী ফাইলটিতে শেষ হবে। হয়ে গেলে, আপনি dupনিজের অস্থায়ী বর্ণনাকারীর কাছে নিজের স্টাটওটিটি পুনরায় সংরক্ষণ করতে পারেন এবং এটি পূর্বের মতো রয়েছে। আপনি এমনকি এই অস্থায়ী বর্ণনাকারীর কাছে লিখতে পারেন, সুতরাং আপনার আসল STDOUT আউটপুট অস্থায়ী ফাইলে গেলে আপনি এখনও বাস্তবে আউটপুট স্টাটটিকে সত্য STDOUT (সাধারণত ব্যবহারকারী) করতে পারেন।

উত্তর

আপনার প্রশ্নের উপরে বর্ণিত পটভূমি তথ্য প্রয়োগ করতে:

শেলটি কোন ক্রমে আদেশগুলি এবং স্ট্রিম পুনঃনির্দেশকে কার্যকর করে?

বাম থেকে ডান.

<command> > file.txt 2>&1

  1. fork একটি নতুন প্রক্রিয়া বন্ধ।
  2. file.txtফাইল ডেস্ক্রিপ্টর 1 (STDOUT) এ এর ​​পয়েন্টারটি খুলুন এবং সঞ্চয় করুন।
  3. STDERR (ফাইল বর্ণনাকারী 2) এফডি 1 পয়েন্ট এখনই যা যা (যা ইতিমধ্যে file.txtঅবশ্যই খোলা আছে )।
  4. exec দ্য <command>

এটি স্পষ্টতই stderr কে প্রথমে stdout এ পুনঃনির্দেশ করে এবং তারপরে ফলাফল stdout file.txt এ পুনঃনির্দেশিত হয়।

এটি কেবলমাত্র একটি টেবিল থাকলে বোঝা যাবে , তবে উপরে বর্ণিত দুটি আছে। ফাইল বর্ণনাকারীরা একে অপরকে পুনরাবৃত্তভাবে নির্দেশ করছে না, "STDERR কে STDOUT এ পুনঃনির্দেশ করুন" তা ভাবার কোনও মানে হয় না। সঠিক চিন্তাটি "STDOR পয়েন্ট যেখানেই STDERR পয়েন্ট"। আপনি যদি পরে STDOUT পরিবর্তন করেন তবে STDERR যেখানেই থাকে সেখানেই থাকে, এটি STDOUT- তে আরও পরিবর্তনগুলির সাথে যাদুকরীভাবে যায় না।


"ফাইল হ্যান্ডেল ম্যাজিক" বিটের জন্য উত্সাহ দেওয়া - যদিও এটি সরাসরি প্রশ্নের উত্তর দেয় না আমি আজ নতুন কিছু শিখলাম ...
ফ্লোরিস

3

অর্ডারটি বাম থেকে ডানদিকে। বাশের ম্যানুয়ালটি আপনি যা জিজ্ঞাসা করেছেন তা ইতিমধ্যে coveredেকে দিয়েছে। REDIRECTIONম্যানুয়ালটির বিভাগ থেকে উদ্ধৃতি :

   Redirections  are  processed  in  the
   order they appear, from left to right.

এবং কয়েক লাইন পরে:

   Note that the order of redirections is signifi
   cant.  For example, the command

          ls > dirlist 2>&1

   directs both standard output and standard error
   to the file dirlist, while the command

          ls 2>&1 > dirlist

   directs   only  the  standard  output  to  file
   dirlist, because the standard error was  dupli
   cated from the standard output before the stan
   dard output was redirected to dirlist.

এটি লক্ষ্য করা গুরুত্বপূর্ণ যে কোনও কমান্ড চালানোর আগে পুনর্নির্দেশটি প্রথমে সমাধান করা হয়েছে! Https://askubuntu.com/a/728386/295286 দেখুন


3

এটি সর্বদা বাম থেকে ডানে ... কখন বাদে

ম্যাথের মতো আমরা যোগ এবং বিয়োগের পূর্বে গুণ এবং বিভাজন ব্যতীত বাম থেকে ডানদিকে করি, গুণক এবং বিভাজনের আগে প্রথম বন্ধনীর (+ -) অপারেশন করা হত।

বাশ শুরুর গাইড অনুসারে এখানে ( ব্যাশ বিগেইনার্স গাইড) ) প্রথমে (বাম থেকে ডান দিকে) প্রথমে যা আসে তার শ্রেণিবিন্যাসের 8 টি আদেশ রয়েছে:

  1. ব্রেস সম্প্রসারণ "{}"
  2. টিলডে সম্প্রসারণ "~"
  3. শেল প্যারামিটার এবং ভেরিয়েবল এক্সপ্রেশন "$"
  4. কমান্ড প্রতিস্থাপন "$ (আদেশ)"
  5. গাণিতিক প্রকাশ "$ ((এক্সপ্রেশন))"
  6. আমরা এখানে "<(তালিকাভুক্ত)" বা "> (তালিকাভুক্ত)" এর কথা বলছি এমন প্রতিস্থাপন প্রক্রিয়া করুন
  7. শব্দ বিভাজন "'<স্পেস> <ট্যাব> <নতুন লাইন>'"
  8. ফাইলের নাম সম্প্রসারণ "*", "?", ইত্যাদি

সুতরাং এটি সর্বদা বাম থেকে ডানে ... যখন বাদে ...


1
পরিষ্কার হতে হবে: প্রক্রিয়া প্রতিস্থাপন এবং পুনঃনির্দেশ দুটি স্বাধীন অপারেশন। আপনি অন্যটি ছাড়া একটি করতে পারেন। প্রক্রিয়া প্রতিস্থাপনের অর্থ এই নয় যে বাশ তার পুনর্নির্দেশ প্রক্রিয়াটি ক্রম পরিবর্তন করার সিদ্ধান্ত নিয়েছে
مور
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.