كيف يمكن لنظام Perl () طباعة الأمر الذي يقوم بتشغيله؟

StackOverflow https://stackoverflow.com/questions/17225

  •  08-06-2019
  •  | 
  •  

سؤال

في لغة Perl، يمكنك تنفيذ أوامر النظام باستخدام system() أو `` (backticcks).يمكنك حتى التقاط إخراج الأمر إلى متغير.ومع ذلك، يؤدي هذا إلى إخفاء تنفيذ البرنامج في الخلفية بحيث لا يتمكن الشخص الذي ينفذ البرنامج النصي من رؤيته.

عادةً ما يكون هذا مفيدًا ولكن في بعض الأحيان أرغب في رؤية ما يحدث خلف الكواليس.كيف يمكنك جعل ذلك يتم طباعة الأوامر المنفذة على الجهاز، وطباعة مخرجات تلك البرامج على الجهاز؟من شأنه أن يكون هذا .bat يعادل "@echo on".

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

المحلول

كما أفهم، سيقوم النظام () بطباعة نتيجة الأمر، ولكن لن يقوم بتعيينه.على سبيل المثال.

[daniel@tux /]$ perl -e '$ls = system("ls"); print "Result: $ls\n"'
bin   dev  home  lost+found  misc  net  proc  sbin     srv  System  tools  var
boot  etc  lib   media       mnt   opt  root  selinux  sys  tmp     usr
Result: 0

سوف تقوم Backticks بالتقاط مخرجات الأمر وعدم طباعته:

[daniel@tux /]$ perl -e '$ls = `ls`; print "Result: $ls\n"'
Result: bin
boot
dev
etc
home
lib

إلخ...

تحديث: إذا كنت تريد طباعة اسم الأمر الذي يكون system()'d أيضًا، على ما أعتقد أرد سمك نهرينهج جيد.تكرر هنا للتوحيد:

sub execute {
    my $cmd = shift;
    print "$cmd\n";
    system($cmd);
}

my $cmd = $ARGV[0];
execute($cmd);

نصائح أخرى

لا أعرف أي طريقة افتراضية للقيام بذلك، ولكن يمكنك تحديد روتين فرعي للقيام بذلك نيابةً عنك:

sub execute {
    my $cmd = shift;
    print "$cmd\n";
    system($cmd);
}

my $cmd = $ARGV[0];
execute($cmd);

ثم شاهده على أرض الواقع:

pbook:~/foo rudd$ perl foo.pl ls
ls
file1   file2   foo.pl

استخدم فتح بدلا من ذلك.ثم يمكنك التقاط إخراج الأمر.

open(LS,"|ls");
print LS;

فيما يلي تنفيذ محدث سيطبع النتائج ويعيدها:

sub execute {
  my $cmd = shift;
  print "$cmd\n";
  my $ret = `$cmd`;
  print $ret;
  return $ret;
}

حسنًا، من المثير للاهتمام كيف يجيب الأشخاص المختلفون على هذا بطرق مختلفة.يبدو لي مثل عضو الكنيست و دانيال فون فسره على أنه الرغبة في رؤية/معالجة stdout للأمر (لم يلتقط أي من الحلول الخاصة بهم stderr fwiw).أظن أرد سمك نهري اقترب.أحد التغييرات التي يمكنك إجراؤها على استجابة Rudd هو استبدال أمر system() المدمج بإصدارك الخاص حتى لا تضطر إلى إعادة كتابة التعليمات البرمجية الموجودة لاستخدام أمر تنفيذ() الخاص به.

باستخدام تنفيذ() الفرعي من منشور Rudd، يمكن أن يكون لديك شيء مثل هذا في الجزء العلوي من التعليمات البرمجية الخاصة بك:

if ($DEBUG) {
   *{"CORE::GLOBAL::system"} = \&{"main::execute"};
}

أعتقد أن هذا سيعمل ولكن يجب أن أعترف أن هذا شعوذة وقد مر وقت طويل منذ أن كتبت هذا الرمز.إليك الكود الذي كتبته منذ سنوات لاعتراض مكالمات النظام على المستوى المحلي (مساحة اسم الاتصال) أو المستوى العالمي في وقت تحميل الوحدة:

  # importing into either the calling or global namespace _must_ be
  # done from import().  Doing it elsewhere will not have desired results.
  delete($opts{handle_system});
  if ($do_system) {
    if ($do_system eq 'local') {
      *{"$callpkg\::system"} = \&{"$_package\::system"};
    } else {
      *{"CORE::GLOBAL::system"} = \&{"$_package\::system"};
    }
  }

هناك أسلوب آخر يمكن دمجه مع الأساليب الأخرى المذكورة في الإجابات وهو استخدام tee يأمر.على سبيل المثال:

open(F, "ls | tee /dev/tty |");
while (<F>) {
    print length($_), "\n";
}
close(F);

سيؤدي هذا إلى طباعة الملفات الموجودة في الدليل الحالي (نتيجة لـ tee /dev/tty) وقم أيضًا بطباعة طول كل اسم ملف مقروء.

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