Подтвердить что ты не робот

Perl one-liner: как ссылаться на имя файла, которое было передано, когда используются переключатели командной строки -ne или -pe

В Perl обычно достаточно легко получить ссылку на аргументы командной строки. Я просто использую $ARGV[0], например, чтобы получить имя файла, который был передан в качестве первого аргумента.

Однако при использовании однострочного Perl он больше не работает. Например, здесь я хочу напечатать имя файла, который я выполняю, если в нем находится определенная строка:

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

Это не работает, потому что ARGV не заполняется, если используется переключатель -n или -p. Есть ли способ обойти это?

4b9b3361

Ответ 1

То, что вы ищете, $ARGV. Цитата из perlvar:

$ARGV

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

Итак, ваш однострочный шрифт станет следующим:

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

Хотя помните, что он будет печатать один раз для каждого матча. Если вы хотите добавить новую строку в печать, вы можете использовать опцию -l.

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

Если вы хотите, чтобы он печатался только один раз для каждого совпадения, вы можете закрыть дескриптор файла ARGV и перейти к следующему файлу:

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

Как указывает Питер Мортенсен, $ARGV и $ARGV[0] - две разные переменные. $ARGV[0] относится к первому элементу массива @ARGV, тогда как $ARGV является скаляром, который является совершенно другой переменной.

Вы говорите, что @ARGV не заполняется при использовании переключателя -p или -n, что неверно. Код, который работает беззвучно, выглядит примерно так:

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
    }
}

Что по существу означает, что использование $ARGV[0] никогда не покажет реальное имя файла, поскольку оно удаляется до его обращения и помещается в $ARGV.