اختبار:
function testfun
set input (cat)
echo $input
end
echo testing123 | testfun
يجب أن ينتج عن هذا "test123" ، لكنه لا ينتج شيئًا.
يعمل بشكل مثالي في باش:
function testfun
{
input="$(cat)"
echo $input
}
echo testing123 | testfun
يمكنك استخدام وظيفة "قراءة" كحل بديل.
function t
while read -l line
echo $line
end
end
لقد فهمت للتو ، أنه لا يعمل في الأسماك ، لأن stdin يتم توجيهه إلى 'set' بدلاً من 'cat'.
هذه المسألة أعمق من مجرد "تعيين" العمل بطريقة معينة. يتم ثمل الأنابيب في وظيفة على الإطلاق. وتعمل وحدة الإدخال / الإخراج التي تم إرسالها إلى إحدى الوظائف ، ولكنها لا تزال غريبة بعض الشيء - يبدو أنها تقوم بتخزين المدخلات مؤقتًا وتسليمها كلها مرة واحدة. لاحظ ما يحدث مع هذه الوظيفة:
~> function meh
cat
end
~> # First, the way it's supposed to work.
~> # As input, we press the keys: a RET b RET control-D
~> cat
a
a
b
b
~> cat | cat
a
a
b
b
~> # Now...
~> meh
a
a
b
b
~> # So far so good, but...
~> cat | meh
a
b
^D
... um...
^D
control-D repeatedly does not work
try control-C
Job 1, “cat | meh” has stopped
~> fg
Send job 1, “cat | meh” to foreground
cat: stdin: Interrupted system call
~> jobs
jobs: There are no jobs
~> # Dear lord.
~> # For completeness...
~> meh | cat
a
b
aD
b
~>
أيضًا ، يتصرف cat | meh | cat
بنفس الطريقة ، كما يفعل cat | begin; cat; end
.
أستطيع أن أخبرك أيضًا أن "القط" الذي يشتكي من مكالمة نظام متقطعة في cat | meh
هو "القط" الأول. هذا هو:
~> cp /bin/cat mycat
~> ./mycat | meh
Job 1, “./mycat | meh” has stopped #after control-C
~> fg
Send job 1, “./mycat | meh” to foreground
mycat: stdin: Interrupted system call
لذلك هناك هذا. من الواضح أن هذا شيء له علاقة بكيفية عمل مكالمات الأسماك وكيف تبني الأنابيب فيها. هل من أحد يعرف عن هذا؟
حسنًا ، أجد هذا الجري
pbpaste | begin; cat; end
بشكل متكرر في قشرة سمكة طازجة ، حيث تكون الحافظة "23 \ n" ، أحيانًا تطبع 23 مرة أخرى ، وستؤدي أحيانًا إلى قفل القشرة ، وعند هذه النقطة لا يمكن لـ control-C فعل شيء. أفترض أن هذا يجب أن يكون حالة عرقية من نوع ما. يا ولد.
في غضون ذلك ، يبدو أن إشارة SIGTTIN تم إرسالها إلى "mycat" ./mycat | begin; cat; end
:
21 SIGTTIN stop process background read attempted from
control terminal
بعد ذلك ، وفقًا لدليل GNU libc: "لا يمكن قراءة العملية من محطة المستخدم أثناء تشغيلها كوظيفة في الخلفية. عندما تحاول أي عملية في وظيفة الخلفية القراءة من الجهاز ، يتم إرسال جميع العمليات في المهمة إشارة SIGTTIN ".
لذا ، يبدو أن "mycat" إما يبدأ في الخلفية ، أو يتم تشغيله ثم وضعه في الخلفية ، عندما يتم نقله إلى وظيفة الأسماك. ربما تساعد هذه المعرفة.
يبدو أن هذه الخلفيات لكلا جانبي الأنبوب ... لكن إعطاء الأمر fg
يسحب العملية من الخلفية مما يسمح لها بالعمل كما يفترض.
~ $ alias pjson='python -m json.tool | pygmentize -l json'
~ $ curl -u smoku -X GET -H "Content-Type: application/json" 'https://jira.......' | pjson
Job 4, 'curl -u smoku -X GET…' has stopped
~ $ fg
Enter host password for user 'smoku': ********
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 593 0 593 0 0 1372 0 --:--:-- --:--:-- --:--:-- 1375
~ $ fg
{
"expand": "renderedFields,names,schema,transitions,operations,editmeta,changelog",
"id": "29874"
}
مزعج بعض الشيء لأنني احتجت إلى إنشاء برنامج نصي مجمّع pjson
في $PATH
بدلاً من الاسم المستعار البسيط ... :(
كمرجع لي ، هذا أيضًا خطأ في openSUSE https://bugzilla.opensuse.org/show_bug.cgi؟id=963548
ياي! أعتقد أنني وجدت الحل الخاص بي! بفضل تعليق gustafj في الإصدار رقم 110 الذي يشرح تركيب أنابيب الأسماك ، توصلت إلى هذا:
function line --argument-names n
cat 1>| tail -n +$n | head -1
end
تؤدي هذه المشكلة ، إلى جانب وظيفة grep الافتراضية لـ grep
، إلى حدوث بعض المشكلات - إذا لم يتم إصلاح هذه المشكلة في أي وقت قريب ، فمن المحتمل أن تتم إزالة الاسم المستعار grep الافتراضي (أو استبداله بـ اختصار ، ربما؟) لتقليل الحدوث على الأقل.
استخدام cat
كما يقترح milieu لا يبدو أنه يحل المشكلة بالنسبة لي ، على Fish 2.3.1 (الذي أدركت للتو أنه متأخر قليلاً ، لكنه الإصدار المعبأ لـ Fedora 25)
يبدو أن هناك فرقًا بين التنفيذ داخل الصدفة وعن سطر الأوامر:
(zsh)$ ./fish -c "read n | grep nothing"
read> lol
(zsh)$ ./fish
(fish)$ read n | grep nothing
read>
# Stuck forever, needs to kill the terminal. ^C, ^Z have no impact.
ربما يمكن أن يساعد هذا في تصحيح المشكلة؟
layus : لا ، هذه # 3805 ، مشكلة حيث لا تستطيع الأسماك نفسها السيطرة على المحطة.
_ أعتقد أن بعض السلوك الأصلي في هذا الصدد قد تغير ، فيما يلي فيما يتعلق بسيد الأسماك / 3.0_
هناك مشكلتان أساسيتان تخطئ فيهما الأسماك هنا ، الأولى هي التخزين المؤقت لوظيفة / إخراج الكتلة (أنا متأكد تمامًا من أن الغلاف الحديث لن يخزن أي شيء مؤقتًا في
بشكل عام ، لديك أوامر خارجية (ومبنية يتم التعامل معها بشكل فعال بنفس الطريقة ، إلى حد كبير) وهي سهلة: إدخال واحد ، ومخرجان ، أحدهما يمكن ربطه بأمر لاحق ، والآخر يجب إعادة توجيهه إلى ملف أو tty. لكن الكتل والوظائف صعبة نظرًا لأنك تقوم بشكل أساسي بتعيين أحد المدخلات (حيث يمكن أن يكون هناك واحدًا فقط) إلى سلسلة من الأوامر الخارجية أو المبنية (التي ستتوسع في النهاية إلى).
بعد قولي هذا ، لا أوافق على أن السلوك الحالي خاطئ. يجب ألا يقرأ (cat)
البيانات التي تم توجيهها إلى الأمر الذي يتم تنفيذه فيه:
mqudsi<strong i="11">@ZBook</strong> /m/c/U/m/Documents> type testfun
testfun is a function with definition
function testfun
set input (cat)
printf "You said '%s'\n" $input
end
mqudsi<strong i="12">@ZBook</strong> ~/r/fish-shell> echo testing123 | testfun
hello
^D
You said 'hello'
أنت تقوم بتوصيل الإدخال إلى الكتلة ، بغض النظر عما إذا كانت المجموعة تستهلك المدخلات ، أو تستهلك جزءًا من الإدخال ، أو تتجاهل الإدخال تمامًا ، فالقط صحيح للاتصال بـ /dev/tty
للإدخال ، والذي يتم تمريره بعد ذلك بشكل صحيح إلى قذيفة للاستبدال في سطر الأوامر. في الواقع ، تم تقديم / تم تقديم (العديد) أخطاء ضد هذا الريبو يشكو من الحالات التي كانت "الأجزاء الفرعية" لا تقرأها من الجهاز عند تنفيذها ببعض مستويات المراوغة. IMHO ، لقد تم كسر bash هنا ، خاصة وأن bash يدعم الأجزاء الفرعية الحقيقية ويقدم عدم التزامن هنا.
السلوك المعطل الوحيد الذي يمكنني قوله ينبع من الحالات التي يتم فيها تشغيل أوامر خارجية في دالة / كتلة ولا تستهلك المدخلات بالكامل:
mqudsi<strong i="19">@ZBook</strong> /m/c/U/m/r/fish-shell> printf 'foo\nbar\n' | begin
head -n1 | read -l line1
head -n2 | read -l line2
echo line1: $line1
echo line2: $line2
end
line1: foo
line2:
TBH أنا مندهش للغاية ولكن هذا يعمل بشكل صحيح:
mqudsi<strong i="23">@ZBook</strong> /m/c/U/m/r/fish-shell> printf 'foo\nbar\n' | begin
/bin/echo 'hi from echo'
cat | read -z from_cat
printf 'from_cat: "%s"' $from_cat
end
hi from echo
from_cat: "foo
bar
"¶
وهذا أيضًا صحيح:
mqudsi<strong i="27">@ZBook</strong> /m/c/U/m/r/fish-shell> printf 'foo\nbar\n' | begin
cat | read -zl from_cat1
cat | read -zl from_cat2
printf 'from_cat1: "%s"\n' $from_cat1
printf 'from_cat2: "%s"\n' $from_cat2
end
from_cat1: "foo
bar
"
from_cat2: ""
خاصة عند الأخذ في الاعتبار خطة تقديم قشور فرعية حقيقية يومًا ما في الأسماك مع التنفيذ غير المتزامن ، أود أن أقول إن سلوك الأسماك فيما يتعلق بالحالة الأصلية المبلغ عنها هنا صحيح. في الواقع ، أنا أميل إلى إغلاق هذه القضية تمامًا ، ما لم يعترض أحد ويمكنه تقديم حجة مقنعة هنا.
على الرغم من أن تقرير الخطأ الأصلي غير صالح ، إلا أن المشكلات التي أثارتها waterhouse هي موضعية cat | meh
ذكرت القضية.
mqudsi<strong i="8">@ZBook</strong> ~/r/fish-shell> cat | meh
a
a
b
b
^D
mqudsi<strong i="9">@ZBook</strong> ~/r/fish-shell>
بعد قولي هذا ، لا أوافق على أن السلوك الحالي خاطئ. يجب ألا يقرأ (cat) البيانات التي تم إدخالها في الأمر الذي تم تنفيذه فيه:
أنا أختلف كثيرا في ذلك!
cat صحيح للاتصال بـ / dev / tty للإدخال
هذا سؤال يتعلق بالنموذج العقلي. أود أن أقول أن القط يتصل بـ "الحالي stdin" للإدخال. إذا لم يتم إعادة توجيه الوظيفة أو الكتلة ، فهذه هي tty. إذا تم إعادة توجيهه ، فهذا كل شيء! لذا فإن الاتصال بـ / dev / tty هنا سيكون غير صحيح.
الشكوى من الحالات التي لا تقرأ فيها "الأجزاء الفرعية" من الجهاز عند تنفيذها ببعض مستويات المراوغة
لاحظ أن هذه كانت كلها حول استبدالات الأوامر "العالمية". على سبيل المثال ، تشغيل echo (fzf)
في سطر الأوامر. في هذه الحالة ، لا يوجد stdin.
لذا فإن ما أود قوله سيعمل على هذا النحو:
echo | echo (cat) # from tty
begin
echo | echo (cat) # from file
end < file
هناك مشكلة ذات صلة (# 1035) تسأل عن stderr في هذه الحالة ، ولا يتم إعادة توجيهها. كانت هذه مشكلة كبيرة في وظيفة math
القديمة ، لأن ذلك حدث مع استبدال الأمر بداخلها ، وبالتالي لا يمكنك إعادة توجيه ذلك.
هذا هو الجزء stdin منه. إذا كانت الدالة تقوم بعمل (cat)
، فهل من المفيد حقًا أن تقرأ دائمًا من tty؟ أو لا يمكنك فقط استخدام </dev/tty
في هذه الحالة؟
أفكار مثيرة للاهتمام.
أعتقد أنه يتلخص في ما إذا كانت الأقواس تشير إلى استبدال بسيط (على سبيل المثال ، "تخيل أن محتويات الأقواس كانت على السطر أعلاه ، قم بتشغيلها حتى الاكتمال ، وقم بتخزين النتيجة في متغير ، واستبدل المتغير هنا") أو " إعادة (معطلة حاليًا) الأجزاء الفرعية. اعتقدت أن الإجماع هو أن الأسماك تفتقر إلى الدعم المناسب ، ولكن النية كانت دائمًا لإصلاح ذلك "في مرحلة ما"
إذا كان هذا هو السابق ، فعندئذ نعم ، أوافق ، يتم كسر السلوك الحالي لأنه إذا قمت بنقل محتويات الأقواس إلى سطر مختلف ، فيجب أن يقرأ بالتأكيد من الإدخال الذي يتم إعادة توجيهه إلى الكتلة.
لكن الأجزاء الفرعية هي مفهوم أقوى بكثير من ذلك ، وهي تتيح لك القيام بأشياء غير ممكنة مع استبدال الأوامر وإنشاء نصوص أكثر استجابة وقدرة. في حين أنه من الممكن تقنيًا توصيل كل ما يتم إدخاله في الكتلة بـ stdin لأمر تم تنفيذه في مجموعة فرعية ، أعتقد أن هذا سيكون غير متوافق مع النموذج العقلي هناك .
ما إذا كانت الأقواس تشير إلى استبدال بسيط (على سبيل المثال ، "تخيل أن محتويات الأقواس كانت على السطر أعلاه ، قم بتشغيلها حتى الاكتمال ، وقم بتخزين النتيجة في متغير ، واستبدل المتغير هنا") أو إذا كانت (متقطعة حاليًا) .
لا أعتقد أن هذه المصطلحات محددة بوضوح بما يكفي لتكون ذات فائدة كبيرة هنا.
بالنسبة لي ، يتعلق الأمر بما هو أكثر طبيعية وأكثر نموذجية وأكثر فائدة.
القراءة من المحطة مفيدة بالتأكيد ، وفي بعض الأحيان تريد القراءة من الجهاز بالرغم من أن لديك أمرًا آخر (على سبيل المثال ، fzf
يقوم بهذا بشكل أساسي حصريًا).
لكنني أعتقد أن القراءة من stdin أكثر نموذجية ، خاصة بالنظر إلى أن الاستخدامات غير التفاعلية لن تقرأ من tty على الإطلاق. وبما أن القراءة من tty لا تزال ممكنة (من خلال إعادة التوجيه </dev/tty
) ، يبدو أنه من الجيد ترك ذلك كخيار ثانوي.
حقيقة أنه لا يوجد مقابل </dev/tty
في النموذج الذي أقترحه تجعلني أعيد النظر في موقفي.
قد لا أكون عميقًا بما يكفي لفهم المناقشة تمامًا. لكني بحاجة إلى حل شيء ما وأتساءل عما إذا كنت بحاجة إلى برنامج نصي باش لحلها.
إنها في الأساس مهمة بسيطة للغاية: أريد توجيه stdout من (z) cat عبر pv إلى mysql cli (أساسًا لاستعادة نسخة احتياطية) ولأنني لا أريد إدخال سلسلة الاتصال ، أريد استخدام وظيفة لها :
function mysqlenv --description connect to mysql server using config from .env
mysql -u (getEnv DB_USERNAME) -p(getEnv DB_PASSWORD) (getEnv DB_DATABASE)
end
أولاً كنت متأكدًا من أن هذا سيعمل لأنه من الواضح أن الأمر هو stdout من الأمر الموجود على الجانب الأيسر ولكني الآن في حيرة من أمري. حسنًا ، إن mysqlenv ليس أمرًا ، إنه وظيفة. الآن أنا هنا أقرأ الكثير من النصوص والكثير من "هذا يجب أن يعمل" ولكن لا شيء يعمل.
ما جربته:
cat -|mysql...
بدون إخراج ؛ لا تحصل mysql على مدخلات ؛ ctr + c موجود mysql ؛ الأنبوب يعمل في الخلفيةmysql... <&0
بدون إخراج ؛ لا تحصل mysql على مدخلات ؛ ctr + c موجود mysql ؛ الأنبوب يعمل في الخلفيةset input (cat); mysql...
بدون إخراج ؛ لا تحصل mysql على مدخلات ؛ ctr + c موجود بالكامل ؛ لم يبق شيء في الخلفيةread -z|mysql...
بدون إخراج ؛ لا تحصل mysql على مدخلات ؛ ctr + c يطبع ^c
مرة أخرى موجه الأوامر الخاص بي: zcat some_backup.sql.gz|pv -s (zsize some_backup.sql.gz)|mysqlenv
. يُظهر حالة الأنبوب عند استخدامه مباشرةً مع mysql (بدون دالة fish في المنتصف) - لذا يجب أن يعمل.
لذا يرجى كيفية إعطاء stdin من الوظيفة إلى stdin لأمر داخل الوظيفة؟
لا تقل أنه يتعين علي إعادة الاتصال لكل سطر عبر while read...
. قد يعمل ولكنه ليس حلاً لأنه بطيء جدًا في العمل معه.
tflori : أبسط بكثير. فقط اترك الأمر كما هو ، دون أي إعادة توجيه. المشكلة ليست مع الأوامر مباشرة في الوظيفة. شيء مثل
function foo
cat
end
يعمل. cat
يحصل على stdin كما ينبغي.
ما لا يحدث عندما يكون في استبدال الأوامر ، هذا عندما تصطدم بهذا الخطأ.
faho هذا يعني أن الوظيفة الأولية يجب أن تعمل؟ لكنها لا تفعل ذلك. ربما روايتي قديمة؟ أنا أستخدم 2.7.1 حاليًا
ربما روايتي قديمة؟ أنا أستخدم 2.7.1 حاليًا
tflori : نعم ، ستريد 3.0.2.
التعليق الأكثر فائدة
تؤدي هذه المشكلة ، إلى جانب وظيفة grep الافتراضية لـ
grep
، إلى حدوث بعض المشكلات - إذا لم يتم إصلاح هذه المشكلة في أي وقت قريب ، فمن المحتمل أن تتم إزالة الاسم المستعار grep الافتراضي (أو استبداله بـ اختصار ، ربما؟) لتقليل الحدوث على الأقل.استخدام
cat
كما يقترح milieu لا يبدو أنه يحل المشكلة بالنسبة لي ، على Fish 2.3.1 (الذي أدركت للتو أنه متأخر قليلاً ، لكنه الإصدار المعبأ لـ Fedora 25)