سؤال

هل يمكن لأحد أن يفسر هذا السلوك؟جري:

#!/bin/sh
echo "hello world" | read var1 var2
echo $var1
echo $var2

لا ينتج عنه أي شيء يتم إخراجه، بينما:

#!/bin/sh
echo "hello world" > test.file
read var1 var2 < test.file
echo $var1
echo $var2

ينتج الناتج المتوقع:

hello
world

ألا ينبغي للأنبوب أن يفعل في خطوة واحدة ما فعلته إعادة التوجيه إلى test.file في المثال الثاني؟لقد جربت نفس الكود مع كل من قذائف Dash و bash وحصلت على نفس السلوك من كليهما.

هل كانت مفيدة؟

المحلول

إضافة حديثة إلى bash هل lastpipe الخيار، الذي يسمح للأمر الأخير في المسار بالعمل في الغلاف الحالي، وليس في الغلاف الفرعي، عندما يتم إلغاء تنشيط التحكم في الوظيفة.

#!/bin/bash
set +m      # Deactiveate job control
shopt -s lastpipe
echo "hello world" | read var1 var2
echo $var1
echo $var2

سوف يخرج بالفعل

hello
world

نصائح أخرى

#!/bin/sh
echo "hello world" | read var1 var2
echo $var1
echo $var2

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

#!/bin/sh
foo="contents of shell variable foo"
echo $foo
(
    echo $foo
    foo="foo contents modified"
    echo $foo
)
echo $foo

تحدد الأقواس منطقة من التعليمات البرمجية التي يتم تشغيلها في غلاف فرعي، ويحتفظ $foo بقيمته الأصلية بعد تعديلها بداخلها.

الآن جرب هذا:

#!/bin/sh
foo="contents of shell variable foo"
echo $foo
{
    echo $foo
    foo="foo contents modified"
    echo $foo
}
echo $foo

الأقواس مخصصة للتجميع فقط، ولا يتم إنشاء غلاف فرعي، و$foo المعدل داخل الأقواس هو نفسه $foo الذي تم تعديله خارجها.

الآن جرب هذا:

#!/bin/sh
echo "hello world" | {
    read var1 var2
    echo $var1
    echo $var2
}
echo $var1
echo $var2

داخل الأقواس، تقوم خاصية القراءة المضمنة بإنشاء $var1 و $var2 بشكل صحيح ويمكنك أن ترى أن صدىهما قد تم تكراره.خارج الأقواس، لم يعد لها وجود.تم تشغيل كافة التعليمات البرمجية داخل الأقواس في غلاف فرعي لأنه أحد مكونات خط الأنابيب.

يمكنك وضع كميات عشوائية من التعليمات البرمجية بين الأقواس، بحيث يمكنك استخدام هذا البناء من الأنابيب إلى كتلة عندما تحتاج إلى تشغيل كتلة من برنامج شل النصي الذي يوزع مخرجات شيء آخر.

لقد تمت الإجابة على هذا السؤال بشكل صحيح بالفعل، ولكن لم يتم ذكر الحل بعد.استخدم ksh، وليس bash.يقارن:

$ echo 'echo "hello world" | read var1 var2
echo $var1
echo $var2' | bash -s

ل:

$ echo 'echo "hello world" | read var1 var2
echo $var1
echo $var2' | ksh -s
hello
world

ksh عبارة عن غلاف برمجة متفوق بسبب التفاصيل الصغيرة مثل هذه.(bash هو الصدفة التفاعلية الأفضل، في رأيي.)

read var1 var2 < <(echo "hello world")

تمت الإجابة على المنشور بشكل صحيح، ولكني أرغب في تقديم بطانة بديلة ربما تكون ذات فائدة.

لتعيين قيم مفصولة بمسافات من الصدى (أو stdout لهذه المسألة) لمتغيرات الصدفة، يمكنك التفكير في استخدام مصفوفات الصدفة:

$ var=( $( echo 'hello world' ) )
$ echo ${var[0]}
hello
$ echo ${var[1]}
world

في هذا المثال، var عبارة عن مصفوفة ويمكن الوصول إلى محتوياتها باستخدام البنية ${var[index]}، حيث الفهرس هو فهرس المصفوفة (يبدأ بالرقم 0).

بهذه الطريقة يمكنك الحصول على أي عدد تريده من المعلمات المخصصة لفهرس المصفوفة ذي الصلة.

رأيي في هذه المشكلة (باستخدام Bash):

read var1 var2 <<< "hello world"
echo $var1 $var2

حسنًا، لقد اكتشفت ذلك!

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

var1=$(echo "Hello")
echo var1

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

set -- $(echo "Hello World")
var1="$1" var2="$2"
echo $var1
echo $var2

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

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

نفذ هذا الأمر

$ echo $$;cat | read a
10637

واستخدم pstree -p لإلقاء نظرة على العمليات الجارية، وسترى غلافًا إضافيًا يتدلى من غلافك الرئيسي.

    |                       |-bash(10637)-+-bash(10786)
    |                       |             `-cat(10785)

يحاول:

echo "hello world" | (read var1 var2 ; echo $var1 ; echo $var2 )

المشكلة، كما ذكر العديد من الأشخاص، هي أن var1 وvar2 تم إنشاؤهما في بيئة قشرة فرعية يتم تدميرها عند خروج تلك القشرة الفرعية.ما ورد أعلاه يتجنب تدمير الغلاف الفرعي حتى يتم صدى النتيجة.الحل الآخر هو:

result=`echo "hello world"`
read var1 var2 <<EOF
$result
EOF
echo $var1
echo $var2
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top