في الغلاف ، ماذا يعني "2> & 1"؟

سئل على ٤ مايو ٢٠٠٩  ·  تمت مشاهدة 1.2M مرة  ·  مصدر

Tristan Havelick picture
في ٤ مايو ٢٠٠٩

في غلاف Unix ، إذا أردت دمج stderr و stdout في الدفق stdout لمزيد من المعالجة ، يمكنني إلحاق ما يلي في نهاية الأمر الخاص بي:

2>&1

لذلك ، إذا كنت أرغب في استخدام head على الناتج من g++ ، فيمكنني فعل شيء مثل هذا:

g++ lots_of_errors 2>&1 | head

لذلك يمكنني رؤية الأخطاء القليلة الأولى فقط.

دائمًا ما أجد صعوبة في تذكر هذا ، ويجب أن أذهب دائمًا للبحث عنه ، ويرجع ذلك أساسًا إلى أنني لا أفهم تمامًا بناء جملة هذه الحيلة المعينة.

هل يمكن لشخص أن يفكك هذا ويشرح الحرف بحرف ماذا يعني 2>&1 ؟

الإجابات

Ayman Hourieh picture
في ٤ مايو ٢٠٠٩
2726

واصف الملف 1 هو الناتج القياسي ( stdout ).
واصف الملف 2 هو الخطأ القياسي ( stderr ).

إليك طريقة واحدة لتذكر هذه التركيبة (على الرغم من أنها ليست دقيقة تمامًا): في البداية ، قد يبدو 2>1 طريقة جيدة لإعادة توجيه stderr إلى stdout . ومع ذلك ، سيتم تفسيره على أنه "إعادة توجيه stderr إلى ملف باسم 1 ". يشير & إلى أن ما يلي وما يسبق هو واصف ملف وليس اسم ملف. لذلك يصبح البناء: 2>&1 .

اعتبر >& عامل دمج إعادة توجيه.

dbr picture
في ٤ مايو ٢٠٠٩
678
echo test > afile.txt

يعيد توجيه stdout إلى afile.txt . هذا هو نفس الشيء

echo test 1> afile.txt

لإعادة توجيه stderr ، عليك القيام بما يلي:

echo test 2> afile.txt

>& هو بناء الجملة لإعادة توجيه دفق إلى واصف ملف آخر - 0 هو stdin ، و 1 stdout ، و 2 stderr.

يمكنك إعادة توجيه stdout إلى stderr بالقيام بما يلي:

echo test 1>&2 # or echo test >&2

أو العكس:

echo test 2>&1

لذا ، باختصار ... 2> يعيد توجيه stderr إلى ملف (غير محدد) ، إلحاق &1 يعيد توجيه stderr إلى stdout.

F. Hauri picture
في ٢٩ أبريل ٢٠١٣
331

بعض الحيل حول إعادة التوجيه

قد يكون لبعض الخصوصية النحوية حول هذا سلوكيات مهمة. هناك بعض العينات الصغيرة حول عمليات إعادة التوجيه و STDERR و STDOUT وترتيب الوسائط.

### 1- الكتابة فوق أم الإلحاق؟ ###

الرمز > يعني إعادة التوجيه .

  • يعني > الإرسال إلى ملف مكتمل بالكامل ، واستبدال الهدف إذا كان موجودًا (راجع ميزة noclobber bash في رقم 3 لاحقًا).
  • >> يعني الإرسال بالإضافة إلى أنه سيتم إلحاقه بالهدف إذا كان موجودًا.

في أي حال ، سيتم إنشاء الملف إذا لم تكن موجودة.

### 2 - سطر أوامر shell يعتمد على الطلب !!

لاختبار ذلك ، نحتاج إلى أمر بسيط يرسل شيئًا ما على كلا المخرجات :

$ ls -ld /tmp /tnt
ls: cannot access /tnt: No such file or directory
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt 2>/dev/null
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

(توقع عدم وجود دليل باسم /tnt ، بالطبع ؛). حسنًا ، لدينا !!

لذلك دعونا نرى:

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1

$ ls -ld /tmp /tnt 2>&1 >/dev/null
ls: cannot access /tnt: No such file or directory

يقوم آخر سطر أوامر بتفريغ STDERR إلى وحدة التحكم ، ويبدو أنه ليس السلوك المتوقع ... لكن ...

إذا كنت ترغب في إجراء بعض تصفية المنشورات حول الإخراج القياسي أو ناتج الخطأ أو كليهما:

$ ls -ld /tmp /tnt | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/<-- & --->/'

$ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->

لاحظ أن سطر الأوامر الأخير في هذه الفقرة هو نفسه تمامًا كما في الفقرة السابقة ، حيث كتبت يبدو أنه ليس السلوك المتوقع (لذلك ، قد يكون هذا سلوكًا متوقعًا).

حسنًا ، هناك القليل من الحيل حول عمليات إعادة التوجيه ، للقيام بعمليات مختلفة على كلا المخرجات :

$ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2  2>&1  | sed 's/^/E: /'
O: drwxrwxrwt 118 root root 196608 Jan  7 12:13 /tmp
E: ls: cannot access /tnt: No such file or directory

ملحوظة: قد يظهر الواصف &9 تلقائيًا بسبب ) 9>&2 .

إضافة: nota! مع الإصدار الجديد من ( >4.0 ) ، هناك ميزة جديدة وبناء جملة أكثر إثارة للقيام بهذا النوع من الأشياء:

$ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
E: ls: cannot access /tnt: No such file or directory

وأخيرًا لتنسيق الإخراج المتتالي:

$ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n
     1  O: drwxrwxrwt 118 root root 196608 Jan  7 12:29 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

إضافة: nota! نفس الصيغة الجديدة في كلا الاتجاهين:

$ cat -n <(ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /'))
     1  O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

حيث يمر STDOUT عبر مرشح معين ، و STDERR إلى مرشح آخر ، وأخيراً يتم دمج كلا المخرجات عبر مرشح أوامر ثالث.

### 3 - كلمة عن الخيار noclobber و >| التركيب ###

يتعلق الأمر بالكتابة :

بينما يوجه set -o noclobber bash بعدم الكتابة فوق أي ملف موجود ، فإن بناء الجملة >| يسمح لك بالمرور عبر هذا القيد:

$ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:15 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:19 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:21 CET 2013

يتم الكتابة فوق الملف في كل مرة ، حسنًا الآن:

$ set -o noclobber

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

مرر بـ >| :

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:18:58 CET 2013

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:19:01 CET 2013

عدم تحديد هذا الخيار و / أو الاستعلام إذا تم تعيينه بالفعل.

$ set -o | grep noclobber
noclobber           on

$ set +o noclobber

$ set -o | grep noclobber
noclobber           off

$ date > $testfile ; cat $testfile
Mon Jan  7 13:24:27 CET 2013

$ rm $testfile

### 4- الحيلة الأخيرة والمزيد ... ###

لإعادة توجيه كلا المخرجات من أمر معين ، نرى أن الصيغة الصحيحة يمكن أن تكون:

$ ls -ld /tmp /tnt >/dev/null 2>&1

لهذه الحالة الخاصة ، هناك صيغة مختصرة: &> ... أو >&

$ ls -ld /tmp /tnt &>/dev/null

$ ls -ld /tmp /tnt >&/dev/null

ملحوظة: إذا كان 2>&1 موجودًا ، فإن 1>&2 هو بناء جملة صحيح أيضًا:

$ ls -ld /tmp /tnt 2>/dev/null 1>&2

### 4 ب- الآن ، سأدعك تفكر في:

$ ls -ld /tmp /tnt 2>&1 1>&2  | sed -e s/^/++/
++/bin/ls: cannot access /tnt: No such file or directory
++drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

$ ls -ld /tmp /tnt 1>&2 2>&1  | sed -e s/^/++/
/bin/ls: cannot access /tnt: No such file or directory
drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

### 4 ج- إذا كنت مهتمًا بمزيد من المعلومات

يمكنك قراءة الدليل الدقيق بالضغط على:

man -Len -Pless\ +/^REDIRECTION bash

في وحدة تحكم ؛-)

Deen John picture
في ٢٩ أكتوبر ٢٠١٦
140

لقد وجدت هذا المنشور الرائع حول إعادة التوجيه: كل شيء عن عمليات إعادة التوجيه

أعد توجيه كل من الإخراج القياسي والخطأ القياسي إلى ملف

الأمر $ &> الملف

يستخدم هذا الخط &> عامل التشغيل

إليك كيف يبدو جدول واصف الملفات بعد أن أعاد Bash توجيه كلا الدفقين:

Enter image description here

كما ترى ، يشير كل من stdout و stderr الآن إلى file . لذا فإن أي شيء يكتب إلى stdout و stderr يُكتب إلى file .

هناك عدة طرق لإعادة توجيه كلا الدفقين إلى نفس الوجهة. يمكنك إعادة توجيه كل دفق واحدًا تلو الآخر:

الأمر $> الملف 2> & 1

هذه طريقة أكثر شيوعًا لإعادة توجيه كلا التدفقات إلى ملف. يتم إعادة توجيه stdout الأول إلى ملف ، ثم يتم تكرار stderr ليكون هو نفسه stdout. لذلك ينتهي كلا الدفقين بالإشارة إلى file .

عندما يرى Bash عدة عمليات إعادة توجيه ، فإنه يعالجها من اليسار إلى اليمين. دعنا ننتقل إلى الخطوات ونرى كيف يحدث ذلك. قبل تشغيل أي أوامر ، يبدو جدول واصف ملفات Bash على النحو التالي:

Enter image description here

يقوم الآن Bash بمعالجة أول إعادة توجيه> ملف. لقد رأينا هذا من قبل وهو يجعل نقطة stdout إلى الملف:

Enter image description here

يرى Next Bash إعادة التوجيه الثانية 2> & 1. لم نشهد إعادة التوجيه هذه من قبل. هذا واحد يكرر واصف الملف 2 ليكون نسخة من واصف الملف 1 ونحصل على:

Enter image description here

تم إعادة توجيه كلا التدفقات إلى ملف.

لكن كن حذرا هنا! جاري الكتابة

الأمر> الملف 2> & 1

ليس مثل الكتابة:

الأمر 2> & 1> ملف

ترتيب عمليات إعادة التوجيه مهم في Bash! يقوم هذا الأمر بإعادة توجيه الإخراج القياسي فقط إلى الملف. سيستمر stderr في الطباعة إلى المحطة. لفهم سبب حدوث ذلك ، دعنا نراجع الخطوات مرة أخرى. لذلك قبل تشغيل الأمر ، يبدو جدول واصف الملف كما يلي:

Enter image description here

الآن تقوم Bash بمعالجة عمليات إعادة التوجيه من اليسار إلى اليمين. يرى أولاً 2> & 1 لذا فإنه يكرر stderr إلى stdout. يصبح جدول واصف الملف:

Enter image description here

الآن يرى Bash عملية إعادة التوجيه الثانية ، >file ، ويقوم بإعادة توجيه stdout إلى ملف:

Enter image description here

هل ترى ما يحدث هنا؟ يشير Stdout الآن إلى الملف ، لكن stderr لا يزال يشير إلى المحطة! كل ما تتم كتابته إلى stderr لا يزال يطبع على الشاشة! لذا كن حذرًا جدًا بشأن ترتيب عمليات إعادة التوجيه!

لاحظ أيضًا أنه في Bash ، الكتابة

الأمر $ &> الملف

هو نفسه تمامًا مثل:

الأمر $> & ملف

Colin Burnett picture
في ٤ مايو ٢٠٠٩
91

تشير الأرقام إلى واصفات الملف (fd).

  • الصفر هو stdin
  • واحد هو stdout
  • اثنان هو stderr

يعيد 2>&1 توجيه fd 2 إلى 1.

يعمل هذا مع أي عدد من واصفات الملفات إذا كان البرنامج يستخدمها.

يمكنك إلقاء نظرة على /usr/include/unistd.h إذا نسيتها:

/* Standard file descriptors.  */
#define STDIN_FILENO    0   /* Standard input.  */
#define STDOUT_FILENO   1   /* Standard output.  */
#define STDERR_FILENO   2   /* Standard error output.  */

ومع ذلك ، فقد قمت بكتابة أدوات C تستخدم واصفات ملفات غير قياسية للتسجيل المخصص حتى لا تراها إلا إذا قمت بإعادة توجيهها إلى ملف أو شيء ما.

paxdiablo picture
في ٤ مايو ٢٠٠٩
58

يرسل هذا التكوين تدفق الخطأ القياسي ( stderr ) إلى الموقع الحالي للإخراج القياسي ( stdout ) - يبدو أن مشكلة العملة هذه قد أهملت من قبل الإجابات الأخرى.

يمكنك إعادة توجيه أي مقبض إخراج إلى آخر باستخدام هذه الطريقة ، لكنها غالبًا ما تستخدم لتوجيه تدفقات stdout و stderr في دفق واحد للمعالجة.

بعض الأمثلة هي:

# Look for ERROR string in both stdout and stderr.
foo 2>&1 | grep ERROR

# Run the less pager without stderr screwing up the output.
foo 2>&1 | less

# Send stdout/err to file (with append) and terminal.
foo 2>&1 |tee /dev/tty >>outfile

# Send stderr to normal location and stdout to file.
foo >outfile1 2>&1 >outfile2

علما بأن هذا الأخير لن يوجه stderr إلى outfile2 - انها الموجهات إلى ما stdout كان عندما واجه الحجة ( outfile1 ) ثم الموجهات stdout إلى outfile2 .

هذا يسمح ببعض الحيل المعقدة للغاية.

Marcus Thornton picture
في ١٩ يوليو ٢٠١٣
21

2 هو خطأ وحدة التحكم القياسية.

1 هو خرج وحدة التحكم القياسي.

هذا هو نظام Unix القياسي ، ويتبع Windows أيضًا POSIX.

على سبيل المثال عند الجري

perl test.pl 2>&1

يتم إعادة توجيه الخطأ القياسي إلى الإخراج القياسي ، حتى تتمكن من رؤية كلا المخرجات معًا:

perl test.pl > debug.log 2>&1

بعد التنفيذ ، يمكنك رؤية كل المخرجات ، بما في ذلك الأخطاء ، في debug.log.

perl test.pl 1>out.log 2>err.log

ثم ينتقل الإخراج القياسي إلى out.log ، والخطأ القياسي إلى err.log.

أقترح عليك محاولة فهم هذه.

wjordan picture
في ٢٥ ديسمبر ٢٠١٦
21

2>&1 هو بنية POSIX shell. هنا تفصيل ، رمز رمزي:


2 : واصف ملف الإخراج " خطأ قياسي ".

>& : تكرار عامل إعادة توجيه الإخراج > ). بالنظر إلى [x]>&[y] ، فإن واصف الملف المشار إليه بعلامة x يكون نسخة من واصف ملف الإخراج y .

1 واصف ملف الإخراج " الإخراج القياسي ".

ينسخ التعبير 2>&1 واصف الملف 1 إلى الموقع 2 ، لذا فإن أي ناتج مكتوب على 2 ("خطأ قياسي") في بيئة التنفيذ ينتقل إلى نفس الملف الذي تم وصفه في الأصل بواسطة 1 ("الإخراج القياسي").


المزيد من التوضيح:

واصف الملف : "عدد صحيح فريد غير سالب لكل عملية يستخدم لتعريف ملف مفتوح لغرض الوصول إلى الملف."

الإخراج / الخطأ القياسي : راجع الملاحظة التالية في قسم إعادة التوجيه في وثائق shell:

يتم تمثيل الملفات المفتوحة بأرقام عشرية تبدأ بصفر. يتم تحديد أكبر قيمة ممكنة بواسطة التنفيذ ؛ ومع ذلك ، يجب أن تدعم جميع التطبيقات ما لا يقل عن 0 إلى 9 ، ضمناً ، للاستخدام بواسطة التطبيق. تسمى هذه الأرقام "واصفات الملفات". القيم 0 و 1 و 2 لها معنى خاص واستخدامات تقليدية ويتم تضمينها في عمليات إعادة توجيه معينة ؛ يشار إليها باسم الإدخال القياسي والإخراج القياسي والخطأ المعياري على التوالي. تأخذ البرامج عادةً مدخلاتها من المدخلات القياسية ، وتكتب الإخراج على الإخراج القياسي. عادة ما يتم كتابة رسائل الخطأ على خطأ معياري. يمكن أن يسبق عوامل إعادة التوجيه رقم واحد أو أكثر (مع عدم السماح بأحرف متداخلة) لتعيين رقم واصف الملف.

Andrioid picture
في ٤ مايو ٢٠٠٩
16

للإجابة على سؤالك: يتطلب الأمر إخراج أي خطأ (يتم إرساله عادةً إلى stderr) ويكتبه إلى الإخراج القياسي (stdout).

هذا مفيد مع ، على سبيل المثال "المزيد" عندما تحتاج إلى الترحيل لجميع المخرجات. بعض البرامج مثل طباعة معلومات الاستخدام في stderr.

لمساعدتك على التذكر

  • 1 = الإخراج القياسي (حيث تقوم البرامج بطباعة الإخراج العادي)
  • 2 = خطأ قياسي (حيث تطبع البرامج أخطاء)

يشير "2> & 1" ببساطة إلى كل شيء يتم إرساله إلى stderr ، إلى stdout بدلاً من ذلك.

أوصي أيضًا بقراءة هذا المنشور حول إعادة توجيه الخطأ حيث يتم تغطية هذا الموضوع بالتفصيل الكامل.

K&#252;&#241;d&#224;&#241; B&#246;r&#224; picture
في ١ أبريل ٢٠٢٠
16

لقد وجدت هذا مفيدًا جدًا إذا كنت مبتدئًا اقرأ هذا

تحديث:
في لينكس أو نظام يونكس ، هناك مكانان يرسل فيهما البرامج المخرجات إلى: الإخراج القياسي (stdout) والخطأ القياسي (stderr) ، ويمكنك إعادة توجيه هذه المخرجات إلى أي ملف.

كما لو فعلت هذا

ls -a > output.txt

لن تتم طباعة أي شيء في وحدة التحكم يتم إعادة توجيه جميع الإخراج (stdout) إلى ملف الإخراج.

وإذا حاولت طباعة محتوى أي ملف لا يخرج ، فهذا يعني أن الإخراج سيكون خطأ مثل إذا قمت بطباعة test.txt غير موجود في الدليل الحالي

cat test.txt > error.txt

سيكون الإخراج

cat: test.txt :No such file or directory

لكن سيكون ملف error.txt فارغًا لأننا نعيد توجيه stdout إلى ملف ليس stderr.

لذلك نحن بحاجة إلى واصف الملف (واصف الملف ليس أكثر من عدد صحيح موجب يمثل ملفًا مفتوحًا. يمكنك القول أن الواصف هو معرف فريد للملف) لإخبار shell بنوع المخرجات التي نرسلها إلى الملف. في نظام Unix / Linux 1 من أجل stdout و 2 لـ stderr .

حتى الآن إذا فعلت هذا

يعني ls -a 1> output.txt أنك ترسل الإخراج القياسي (stdout) إلى output.txt.

وإذا فعلت هذا

يعني cat test.txt 2> error.txt أنك ترسل خطأ قياسي (stderr) إلى error.txt.

يستخدم &1 للإشارة إلى قيمة واصف الملف 1 (stdout).

الآن إلى النقطة يعني 2>&1 "إعادة توجيه stderr إلى نفس المكان الذي نعيد فيه توجيه stdout"

الآن يمكنك فعل هذا

cat maybefile.txt > output.txt 2>&1

سيتم إعادة توجيه كل من الإخراج القياسي (stdout) والخطأ القياسي (stderr) إلى output.txt.

بفضل Ondrej K. للإشارة