سؤال

لقد كنت تحت الانطباع بأن العمليات على نظام التشغيل لديها ثلاثة تدفقات قياسية: stdin, stdout, and stderr. لقد اعتقدت أيضًا أن محرري النصوص مثل VIM يعملون من خلال تولي المدخلات stdin وإرسال شخصيات الهروب من Ansi stdout. ومع ذلك ، فإن وجهة نظري حول كيفية عدم صياغة المترجمين المترجمين في خط الأوامر في هذه الحالة:

عندما أقوم بتشغيل الأمر C:\cygwin\bin\bash.exe, ، لقد طُلب مني مع:

Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Users\masson>C:\cygwin\bin\bash.exe
bash-3.2$ 

... ولكن عندما أقوم بتشغيله في Java مع المقتطف التالي ، يكون دفق Stdin فارغًا:

ProcessBuilder pb = new ProcessBuilder("C:\\cygwin\\bin\\bash.exe");
pb.redirectErrorStream(true);
Process proc = pb.start();
final InputStream in = proc.getInputStream();

new Thread(new Runnable() {
  public void run() {
    // Blocks forever...
    in.read(new byte[1024]);
  }
}).start();

ما الذي يجري هنا؟ لقد قيل لي إن bash.exe يعمل في الوضع التفاعلي. هل هذا يعني أنه لا يتم استخدام التدفقات القياسية؟ كيف لا يزال بإمكاني العمل مع هذه البرامج ، وفي النهاية ، كيف يمكنني تنفيذ نسختي الخاصة من cmd.exe؟ أعتقد أنني لا أفهم شيئًا أساسيًا حول كيفية عمل المترجمين الفوريين في خط القيادة ...

(أي روابط إلى المقالات التي تناقش الموضوعات ذات الصلة ستكون موضع تقدير كبير. لم يكن لدي الكثير من الحظ في البحث. أوه ، وسؤال أخير ، هل تعامل تدفقات قياسية بشكل مختلف في Windows عن معظم أنظمة التشغيل التي تشبه Unix؟)

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

المحلول

التواجد في الوضع التفاعلي لا يعني أنه لا يتم استخدام التدفقات القياسية. ولكن في هذه الحالة ، من المرجح أن يكون باش يعمل عدم-الوضع النشط (يكتشف أنه لا يتحدث مباشرة إلى التطبيق الطرفي ، لذلك يفترض أنه يتم استخدامه برمجيًا ، وبالتالي لا يطبع لافتة الترحيب). في هذه الحالة ، لا تزال التدفقات القياسية تستخدم ، فهو لا يتم إخراج أي شيء.

كما أشار Ergosys ، لا يمكنك الاعتماد عليها حقًا in.read(new byte[1024]) بالعودة قبل أن تقرأ البايتات الكاملة الكاملة ، على الرغم من أنه من الجيد أن نفترض أنه لن يعود بالتأكيد قبل قراءة بايت واحد على الأقل ، وأعتقد أن هذه هي المشكلة هنا - أنت لا تحصل على حتى بايت واحد من الإخراج.

حاول تمرير "-i" إلى bash للحصول عليها في الوضع التفاعلي.

نصائح أخرى

يمكن لأي برنامج باستخدام مكتبة C القياسية معرفة ما إذا كان يتحدث إلى جهاز TTY (ويعرف أيضًا باسم سطر الأوامر) باستخدام الدالة ISATTY (). ربما يكتشف Bash أنه يتحدث إلى أنبوب بدلاً من Tty ولا يخرج موجهًا.

أنا رجل بيثون أكثر من رجل Java (لذلك كل ما أقوله لك هو تخمينات سريعة من Javadoc) ، لكن يبدو أنك تقوم بإعداد مسدود متعدد العمليات.

in.read(new byte[1024]); لن تعود حتى يتم قراءة 1024 بايت من البيانات و bash.exe لا يخرج 1024 بايت بالكامل قبل التوقف عن انتظار المدخلات. (للقيام بذلك ، استخدم proc.getOutputStream() وإطعامها بعض الأوامر للرد عليها.)

نتيجة لذلك ، تحصل على جافا في انتظار أن ترد باش وينتظر جافا للرد والكلاهما راضٍ تمامًا عن الانتظار حتى وفاة الكون دون الشعور بالملل أو التعب.

نصيحتي هي الاستخدام in.available() قبل كل مكالمة إلى in.read() لتجنب الحظر. وبهذه الطريقة ، يمكنك التبديل ذهابًا وإيابًا بين تغذية البيانات وسحبها دون أن تتعثر.

في الواقع ، من المحتمل أن يكون أبسط بكثير وسانر فقط لفه في أ BufferedReader.

تحديث من التعليق: أيضًا ، عندما تكتشف أدوات مثل Bash أن stdin ليست محطة (انظر مكالمة نظام isatty) ، انهم العازلة في قطع ضخمة (4K أو أكثر) على افتراض أن المدخلات غير تفاعلية. لست متأكدًا مما إذا كان سيساعد ، لكن حاول بدء تشغيل Bash مع علم -i.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top