Come può il sistema system() di Perl stampare il comando che sta eseguendo?

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

  •  08-06-2019
  •  | 
  •  

Domanda

In Perl, potete eseguire comandi di sistema usando system() o `` (backtick).Puoi anche catturare l'output del comando in una variabile.Tuttavia, questo nasconde l'esecuzione del programma in background in modo che la persona che esegue lo script non possa vederla.

Normalmente questo è utile ma a volte voglio vedere cosa succede dietro le quinte.Come si fa in modo che i comandi eseguiti vengano stampati sul terminale e l'output di quei programmi venga stampato sul terminale?Questo sarebbe il .bat equivalente di "@echo on".

È stato utile?

Soluzione

A quanto ho capito, system() stamperà il risultato del comando, ma non lo assegnerà.Per esempio.

[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

I backtick cattureranno l'output del comando e non lo stamperanno:

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

eccetera...

Aggiornamento: Se vuoi stampare anche il nome del comando che viene system(), penso Ruddl'approccio è buono.Ripetuto qui per consolidamento:

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

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

Altri suggerimenti

Non conosco alcun modo predefinito per farlo, ma puoi definire una subroutine che lo faccia per te:

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

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

E poi vederlo in azione:

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

Utilizzare invece aperto.Quindi puoi acquisire l'output del comando.

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

Ecco un'esecuzione aggiornata che stamperà i risultati e li restituirà:

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

Hmm, interessante come persone diverse rispondano a questi modi diversi.Mi sembra mk E Daniele Fone lo ha interpretato come se volesse vedere/manipolare lo stdout del comando (nessuna delle loro soluzioni cattura stderr fwiw).Penso Rudd si avvicinò.Una svolta che potresti apportare alla risposta di Rudd è sovrascrivere il comando system() integrato con la tua versione in modo da non dover riscrivere il codice esistente per utilizzare il suo comandoexecute().

usando il suo subexecutive() dal post di Rudd, potresti avere qualcosa di simile nella parte superiore del tuo codice:

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

Penso che funzionerà, ma devo ammettere che si tratta di voodoo ed è passato un po' di tempo dall'ultima volta che ho scritto questo codice.Ecco il codice che ho scritto anni fa per intercettare le chiamate di sistema a livello locale (spazio dei nomi chiamante) o globale al momento del caricamento del modulo:

  # 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"};
    }
  }

Un'altra tecnica da combinare con le altre menzionate nelle risposte è usare il file tee comando.Per esempio:

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

Questo stamperà entrambi i file nella directory corrente (come conseguenza di tee /dev/tty) e stampa anche la lunghezza di ciascun nome file letto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top