Странный вывод `pwd` из perl - PullRequest
1 голос
/ 03 июля 2011

У меня очень короткий учебный Perl-скрипт:

#!/usr/bin/perl
print "The date is ",`date`;
print "The date is `date`",".\n";
$directory=`pwd`;
print "\nThe current directory is $directory.";

и вывод:

The date is Sat Jul  2 17:04:58 PDT 2011
The date is `date`.

The current directory is total 20
-rwxr-xr-x 1 yan yan 433 2011-07-02 15:58 36
-rwxr-xr-x 1 yan yan 313 2011-07-02 16:29 43
-rwxr-xr-x 1 yan yan 116 2011-07-02 16:51 45
-rwxr-xr-x 1 yan yan 149 2011-07-02 16:53 46
-rwxr-xr-x 1 yan yan 145 2011-07-02 17:02 47

Но если я просто запущу pwd, я получу:

yan@ubuntu:~/bin/blackperl$ pwd
/home/yan/bin/blackperl

Есть логическое объяснение тайне здесь?Большое спасибо!

Ответы [ 4 ]

7 голосов
/ 03 июля 2011

Я тоже не могу раскрыть тайну, но вы можете попробовать использовать модуль Perl Core Cwd вместо команды pwd:

use warnings;
use strict;
use Cwd;
my $dir = getcwd();
print "$dir\n";

Одним из преимуществ является то, что Cwd является более портативным, чем pwd.

См. Также: Эквиваленты UNIX 'command' в Perl

3 голосов
/ 05 июля 2011

Возможное объяснение тайны :

У вас есть программа с именем pwd в пути поиска команд (т.е. в одном из каталогов, названных переменной среды PATH), которыеделает эти странные вещи.При выполнении pwd в интерактивной оболочке (bash) или в сценарии оболочки (dash) вы получаете команду buildin pwd, которая печатает текущий рабочий каталог, как и должно быть.

С другой стороныВ вашей исходной строке Perl

$directory=`pwd`;

Perl не вызывает системную оболочку с помощью функции C system(), а вместо этого напрямую выполняет команду pwd в пути (используя execvp() вызов в разветвленном процессе), поскольку команда выглядит достаточно простой ( простая команда , в терминологии bash).Если этот pwd двоичный файл не является обычным /bin/pwd двоичным файлом (который также просто печатает текущий каталог), а вместо этого выполняет что-то вроде ls -l, мы получаем наблюдаемое поведение.

РеальноеРешение было бы исправить вашу PATH и / или удалить поддельный pwd двоичный файл.Используйте which pwd, чтобы узнать, где он находится (или type -a pwd на bash).

Решение со стороны Perl состоит в том, чтобы вызвать вызов оболочки:

$directory=`pwd;`;

Это заставляет Perl вызывать оболочку вместо непосредственного выполнения программы.(В целом, любой метасимвол оболочки имеет такой эффект. Это описано только для системной функции Perl , а не для оператора quote-execute .)

В этом случае Perl будет вызывать /bin/sh, который в Ubuntu (по крайней мере в текущих версиях, я не уверен насчет вашего 9.10) равен dash (оболочка Debian Almquist) вместо bash (GNU's Bourne Again)Ракушка).Dash - намного более простая (и более быстрая) реализация sh, чем bash, но для таких вещей, как pwd, не должно быть никакой разницы (это тоже встроенная функция в моем dash), если у вас нет псевдонимов или функций оболочкиопределяется в одной оболочке, а не в другой.

Конечно, лучшим решением будет использование модуля Perl Cwd , как рекомендуется в ответеtoolic .


Благодарю ikegami за объяснение мне семантики оператора backticks в комментариях к вопросу.

2 голосов
/ 03 июля 2011

Здесь тоже работает нормально (SUSE Linux Enterprise Server). Я понятия не имею, почему $directory выплюнул бы вывод ls.

ETA: Запустите это из командной строки:

perl -e 'print "$ENV{PWD}\n";'

и скажите мне, что вывод.

1 голос
/ 03 июля 2011

У меня тоже отлично работает. Мне интересно, может ли это быть как-то связано с псевдонимом оболочки или функцией оболочки. Вы можете связать команду с другой командой в bash следующим образом:

doug@supermicro:~$ alias pwd='ls -la'

Вот еще псевдоним: http://en.wikipedia.org/wiki/Alias_%28command%29

Хотя я не могу понять, почему команда оболочки, запускаемая программой Perl, имеет доступ к другому набору псевдонимов из набора, к которому у вас есть доступ.

Запускаете ли вы эту программу из командной строки или запускаете ее через другой процесс? (например, скрипт CGI, который запускается учетной записью пользователя Apache)

Вы также можете определить функции оболочки с теми же именами, что и у внешних команд, и которые запускаются вместо внешних команд, но это не объясняет, почему вы получаете нормальный вывод непосредственно из командной строки.

...