2012-02-05 9 views
13

In Perl, normalmente è abbastanza facile ottenere un riferimento agli argomenti della riga di comando. Io uso semplicemente $ARGV[0] per esempio per ottenere il nome di un file che è stato passato come primo argomento.Perl one-liner: come fare riferimento al nome file passato quando si usano gli switch -line o -pe o -pe

Quando si utilizza un rivestimento Perl, tuttavia, sembra non funzionare più. Ad esempio, qui voglio stampare il nome del file che sto scorrendo se una certa stringa si trova al suo interno:

perl -ne 'print $ARGV[0] if(/needle/)' haystack.txt 

Questo non funziona, perché ARGV non viene popolata quando il Viene utilizzato l'interruttore -n o -p. C'è un modo per aggirare questo?

risposta

21

Quello che stai cercando è $ARGV. Citazione di perlvar:

$ARGV 

Contains the name of the current file when reading from <> . 

Così, il vostro one-liner sarebbe diventato:

perl -ne 'print $ARGV if(/needle/)' haystack.txt 

Anche se essere consapevoli che verrà stampata una sola volta per ogni partita. Se si desidera aggiungere una nuova riga alla stampa, è possibile utilizzare l'opzione -l.

perl -lne 'print $ARGV if(/needle/)' haystack.txt 

Se si desidera stampare solo una volta per ogni partita, è possibile chiudere l'handle di file ARGV e renderlo passare al file successivo:

perl -lne 'if (/needle/) { print $ARGV; close ARGV }' haystack.txt haystack2.txt 

Come Peter Mortensen fa notare, $ARGV e $ARGV[0] sono due diverse variabili. $ARGV[0] fa riferimento al primo elemento dell'array @ARGV, mentre $ARGV è uno scalare che è una variabile completamente diversa.

Si dice che @ARGV non viene popolato quando si utilizza lo switch -p o -n, che non è vero. Il codice che funziona silenziosamente è qualcosa di simile:

while (@ARGV) { 
    $ARGV = shift @ARGV;   # arguments are removed during runtime 
    open ARGV, $ARGV or die $!; 
    while (defined($_ = <ARGV>)) { # long version of: while (<>) { 
     # your code goes here 
    } continue {     # when using the -p switch 
     print $_;     # it includes a print statement 
    } 
} 

che in sostanza significa che usare $ARGV[0] non mostrerà mai il nome del file vero e proprio, in quanto viene rimosso prima che si accede, e posto in $ARGV.

+0

Forse la differenza tra $ ARGV [0] e $ ARGV dovrebbe essere spiegata. E perché il primo, ma non il secondo, funziona in questo caso particolare. –

+0

@PeterMortensen Suppongo che non faccia male. – TLP

+0

Come posso stampare il file insieme ad es. la riga corrispondente, ad esempio nel comando 'perl -ne 'print" $ ARGV: $ line "if/pattern /' $ (grep -rl" pattern ")', cosa dovrei inserire invece di * $ line *? – tonix

Problemi correlati