Как присвоить элемент @ARGV переменной $, а затем распечатать его?

Его часто задавали по-разному, однако я собираюсь спросить еще раз, потому что я не полностью понимаю применение @ARGV и потому что я не нашел ответа на этот вопрос (или, что более вероятно, я не понимаю ответы и уже предоставленные решения).

Вопрос в том, почему ничего не читается из командной строки? Кроме того, как мне расшифровать сообщение об ошибке,

Использование неинициализированного значения $name в конкатенации (.) или строки в ... ?

Я так понимаю, что @ARGV — это массив, в котором хранятся аргументы (файлы) командной строки. Я также понимаю, что им можно манипулировать, как и любым другим массивом (учитывая, что индекс $ARGV[0] не совпадает с функцией командной строки переменной имени файла, $0). Я понимаю, что в цикле while алмазный оператор автоматически shift первый элемент @ARGV будет $ARGV[ ], прочитав строку на входе.

Чего я не понимаю, так это того, как присвоить элемент @ARGV скалярной переменной, а затем распечатать датум. Например (концепция кода взята из Learning Perl),

my $name = shift @ARGV;

while (<>) {
    print “The input was $name found at the start of $_\n”;
    exit;
}

В соответствии с кодом вывод $name пуст; если бы я опустил shift(), $name вывел бы 0, как я считаю, и должно быть в скалярном контексте, но это не отвечает на вопрос, почему ввод из командной строки не принимается. Ваши идеи будут оценены.

Спасибо.


person Den    schedule 01.11.2020    source источник
comment
Если это вся ваша программа (с use warnings; и use strict; в начале), то когда вы запускаете ее с аргументом, например prog.pl hello, она будет ожидать ввода, так как <> читает STDIN, если никакие файлы не переданы в программа. (Поскольку вы shift-ed из @ARGV, в котором было только hello слово, в нем ничего нет, и поэтому <> ждет.) Затем вы нажимаете Enter, и он запускает оператор печати с hello в переменной $name. (Если вы ничего не даете программе при запуске, тогда $name пусто, но вы, кажется, знаете об этом.) Я не понимаю, почему/как она ведет себя по-другому для вас?   -  person zdim    schedule 01.11.2020
comment
В цикле while (<>) любой ввод, считываемый с терминала, назначается $_ -- и вы не печатаете его, поэтому его невозможно увидеть. Однако это по-прежнему не объясняет, как вы можете сделать $name пустым (если вы передаете аргумент программе при ее запуске). Значит, что-то не так в вашем описании проблемы? Обратите внимание: то, что находится в @ARGV, воспринимается <> как имена файлов, и эти файлы открываются и читаются построчно.   -  person zdim    schedule 01.11.2020
comment
Найдите специальные переменные Perl на странице perlvar. Найдите краткие пояснения к сообщениям об ошибках на странице perldiag.   -  person zdim    schedule 02.11.2020
comment
Отлично, так что это прояснилось, в частности, с ответом Икегами :). Это хороший вопрос, тщательно написанный. Обратите внимание, что я упоминал выше, что если вы предоставляете аргументы сценарию, то, когда выполнение доходит до <>, эти аргументы обрабатываются как файлы (если они не были удалены из @ARGV ранее), которые открываются и читаются построчно. Это очень полезно, поскольку вы можете использовать while (<>) для либо обработки STDIN построчно (запрашивая и ожидая ввода, либо считывая ввод, переданный в программу) или для обработки файлов. Гибкий :)   -  person zdim    schedule 02.11.2020


Ответы (1)


my $name = shift @ARGV; действительно назначает первый аргумент программы. Если вы получаете Use of uninitialised value $name in concatenation (.) or string at ..., это потому, что вы не предоставили никаких аргументов своей программе.

$ perl -we'my $name = shift(@ARGV); print "My name is $name.\n"'
Use of uninitialized value $name in concatenation (.) or string at -e line 1.
My name is .

$ perl -we'my $name = shift(@ARGV); print "My name is $name.\n"' ikegami
My name is ikegami.

Нет абсолютно никаких проблем с последующим использованием <>.

$ cat foo
foo1
foo2

$ cat bar
bar1
bar2

$ perl -we'
   print "(\@ARGV is now @ARGV)\n";
   my $prefix = shift(@ARGV);

   print "(\@ARGV is now @ARGV)\n";
   while (<>) {
      print "$prefix$_";
      print "(\@ARGV is now @ARGV)\n";
   }
' '>>>' foo bar
(@ARGV is now >>> foo bar)
(@ARGV is now foo bar)
>>>foo1
(@ARGV is now bar)
>>>foo2
(@ARGV is now bar)
>>>bar1
(@ARGV is now )
>>>bar2
(@ARGV is now )
person ikegami    schedule 01.11.2020
comment
Благодарю вас за уточнение правильности сценария и мою оплошность, связанную с тем, что я не предоставил ввод в командной строке, как ожидал сценарий. Я не знаком с вашим методом написания и запуска скрипта из командной строки, но я почитаю ваши примеры. - person Den; 02.11.2020
comment
Для чего используются три угловые скобки >>>? - person Den; 02.11.2020
comment
Тот факт, что я предоставил программу в командной строке, не имеет значения. То же самое произошло бы, если бы программа была в файле. Так что просто представьте, что perl -we'...' это perl foo.pl или ./foo.pl /// Это аргумент. Использование имени не имело смысла - person ikegami; 02.11.2020
comment
@Den Когда вы запускаете из командной строки perl -e'...' то, что находится между '', обрабатывается как программа Perl и выполняется (это -e). Удобно для быстрых тестов (или, возможно, даже из-за нехватки сценариев bash или чего-то подобного). Так же есть много удобных переключателей, например perl -ne'...' file откроет file и пройдется по нему построчно применяя код в '' (это -n). См. perlrun. В оболочке bash вы даже можете распределить ее по нескольким строкам, поэтому приведенную выше программу можно скопировать и вставить в вашу оболочку, а затем нажать Enter, чтобы запустить ее. - person zdim; 02.11.2020
comment
@Den Я слышал об этом, никогда не видел. Извините за неровное начало — любой язык программирования может сокрушить вас, если что-то просто бросить вам в лицо, а Perl, в частности, — мощный инструмент. Но один хороший момент заключается в том, что должно быть легко освоить основы (относительно), так что, возможно, эта книга просто не справилась с этой темой? - person zdim; 05.11.2020
comment
@Den Если эта книга работает на вас в целом, отлично (я не могу рекомендовать или оспаривать ее, так как не знаю ее). Если нет, то наверняка есть выбор. Классикой является Learning Perl (а тут еще нужен материал хотя бы Intermediate Perl), но новых, сильно переработанных изданий (после второго) я не видел. Я видел отрывки из Modern Perl, которые можно бесплатно загрузить с веб-сайта автора, и мне понравилось то, что я увидел. - person zdim; 05.11.2020
comment
@Den Я предлагаю удалить эти комментарии (начиная с моих острот), поскольку они не по теме и могут отвлекать от ответа. Дай мне знать, когда увидишь их и будешь готов. Приятного вам обучения :) - person zdim; 05.11.2020
comment
@Дэн, я не волнуюсь. Много полезной информации в этих комментариях - person ikegami; 05.11.2020