كيف يمكن لنظام Perl () طباعة الأمر الذي يقوم بتشغيله؟
سؤال
في لغة 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
) وقم أيضًا بطباعة طول كل اسم ملف مقروء.