Поиск канала и редиректов в perl @ARGV

При написании традиционной программы Unix/Linux perl предоставляет ромбовидный оператор ‹>. Я пытаюсь понять, как проверить, не передан ли вообще аргумент, чтобы скрипт Perl не сидел в цикле ожидания для STDIN, когда этого не должно быть.

#!/usr/bin/perl
# Reading @ARGV when pipe or redirect on the command line
use warnings;
use strict;

while ( defined (my $line = <ARGV>)) { 
    print "$ARGV: $. $line" if ($line =~ /eof/) ;  # an example
    close(ARGV) if eof;
}

sub usage {
    print  << "END_USAGE" ;
    Usage:
        $0 file
        $0 < file
        cat file | $0    
END_USAGE
    exit();
}

Несколько запусков вывода показывают, что ‹> работает, но без аргументов мы ждем ввода STDIN, а это не то, что мне нужно.

$ cat grab.pl | ./grab.pl
-: 7     print "$ARGV: $. $line" if ($line =~ /eof/) ;  # an example
-: 8     close(ARGV) if eof;

$ ./grab.pl < grab.pl
-: 7     print "$ARGV: $. $line" if ($line =~ /eof/) ;  # an example
-: 8     close(ARGV) if eof;

$ ./grab.pl grab.pl
grab.pl: 7     print "$ARGV: $. $line" if ($line =~ /eof/) ;  # an example
grab.pl: 8     close(ARGV) if eof;

$ ./grab.pl
^C
$ ./grab.pl
[Ctrl-D]
$

Первая мысль — проверить $#ARGV, который содержит номер последнего аргумента в @ARGV. Затем я добавил тест к приведенному выше сценарию перед циклом while следующим образом:

if ( $#ARGV < 0 ) {   # initiated to -1 by perl
    usage();
}

Это не дало желаемых результатов. $#ARGV равно -1 для перенаправления и конвейера в командной строке. Запустив эту проверку (grabchk.pl), проблема изменилась, и я не могу прочитать содержимое файла с помощью ‹> в канале или случаях перенаправления.

$ ./grabchk.pl grab.pl
grab.pl: 7     print "$ARGV: $. $line" if ($line =~ /eof/) ;
grab.pl: 8     close(ARGV) if eof;

$ ./grabchk.pl < grab.pl
    Usage:
        ./grabchk.pl file
        ./grabchk.pl < file
        cat file | ./grabchk.pl

$ cat grab.pl | ./grabchk.pl
    Usage:
        ./grabchk.pl file
        ./grabchk.pl < file
        cat file | ./grabchk.pl

Есть ли лучший тест, чтобы найти все параметры командной строки, переданные в perl оболочкой?


person Debinix    schedule 17.09.2011    source источник
comment
Это отступление, но никогда не пишите if ($#array < 0), если можно написать if (@array == 0) или unless (@array). Использование последнего индекса в массиве, когда вам нужно количество элементов в массиве, не говорит о том, что вы имеете в виду.   -  person hobbs    schedule 17.09.2011
comment
я буду иметь это в виду   -  person Debinix    schedule 17.09.2011


Ответы (2)


Вы можете использовать оператор проверки файлов -t, чтобы проверить, открыт ли дескриптор файла STDIN для Телетайп.

Поэтому, если он открыт для терминала и аргументов нет, вы отображаете текст использования.

if ( -t STDIN and not @ARGV ) {
    # print usage and exit
}
person Oleg Pavliv    schedule 17.09.2011
comment
Спасибо за тест, любые идеи, как получить доступ к командной строке оболочки - person Debinix; 17.09.2011
comment
Пожалуйста. Я не думаю, что вы можете получить доступ к командной строке, кроме чтения аргументов из @ARGV. - person Oleg Pavliv; 17.09.2011
comment
Ваша программа Perl, просматривая свои аргументы, ничего не видит перед каналом или после оператора перенаправления. Оболочка анализирует их и связывает с файловыми дескрипторами для доступа вашей программы. См. эту ветку Perlmonks о том, как ваша программа может определить, к чему подключены эти файловые дескрипторы. Короче говоря: это зависит от платформы, и лучше всего использовать программу lsof. - person ajk; 17.09.2011
comment
Спасибо, я посмотрю на это, поскольку побочным эффектом использования ‹› в канале и перенаправлений является то, что алмазные операторы заменяют имя файла ($ARGV) на «-», если @ARGV пуст, и узнать фактическое имя файла можно быть важным в зависимости от цели скрипта. - person Debinix; 17.09.2011
comment
@Debinix, зачем тебе командная строка? Как вы думаете, почему для запуска вашей программы использовалась командная строка bash? Как вы думаете, какое значение имеет знать командную строку, если она была? - person ikegami; 17.09.2011
comment
@ikegami, это была первоначальная мысль для теста. Имея доступ к полным аргументам командной строки, которые могут помочь решить мою проблему. Возможно, вы правы, это все равно не помогло бы, т.е. действительно ли я получил бы доступ к символам '‹' и вертикальной черте '|'? Также в этой ситуации трудно найти настоящие имена файлов, но этот вопрос — новая тема. - person Debinix; 18.09.2011

используйте оператор -t, чтобы проверить, подключен ли STDIN к tty, когда вы используете перенаправление канала или оболочки, он вернет false, поэтому вы используете

if ( -t STDIN and not @ARGV ){ exit Usage(); }
person bogey    schedule 17.09.2011
comment
-1: это просто повторяет часть предыдущего ответа Олега Павлива. - person tripleee; 17.09.2011