Как я могу узнать, какой скрипт, программа или оболочка выполняли мой Perl-скрипт? - PullRequest
7 голосов
/ 16 декабря 2011

Как мне определить, какой скрипт, программа или оболочка выполнили мой Perl-скрипт?

Пример: я мог бы захотеть иметь читабельный вывод для человека, если он выполняется из оболочки (настраивается для каждого типа оболочки), вывод другого типа, если он вызывается как скрипт из другого сценария perl, и машиночитаемый формат, если выполняется из такая программа, как сервер непрерывной интеграции.

Мотивация: у меня есть инструмент, который изменяет свой вывод в зависимости от того, какая оболочка его выполняет. Обычно я реализую это поведение в качестве опции для скрипта, но дизайн этого инструмента не допускает опций. Другие оболочки имеют переменные среды, которые указывают, какая оболочка работает. Я работаю над патчем для поддержки Powershell, который не имеет такой специальной переменной.

Редактировать: Многие из этих ответов относятся к Linux. К сожалению, Powershell для Windows. getppid, переменная $ENV{SHELL} и обнуление до ps в этом случае не помогут. Этот скрипт должен работать кроссплатформенно.

Ответы [ 5 ]

5 голосов
/ 16 декабря 2011

Вы используете getppid () .Возьмите этот фрагмент в child.pl:

my $ppid = getppid();
system("ps --no-headers $ppid");

Если вы запустите его из командной строки, system покажет bash или подобное (среди прочего).Выполните его с system("perl child.pl"); в другом скрипте, например, parent.pl, и вы увидите, что perl parent.pl выполнил его.

Чтобы захватить только имя процесса с аргументами (спасибо ikegami за правильное ps синтаксис):

my $ppid = getppid();
my $ps = `ps --no-headers -o cmd $ppid`;
chomp $ps;

РЕДАКТИРОВАТЬ: Альтернативой этому подходу может быть создание мягких ссылок на ваш сценарий, заставить различные контексты использовать разные ссылки для доступа к вашему сценарию иОсмотрите $0, чтобы построить вокруг него логику.

3 голосов
/ 17 декабря 2011

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

  1. Функция, которая может вызываться внутри Perl-программы.Это, вероятно, вернет структуру данных Perl.Это гораздо проще, быстрее и надежнее, чем вывод синтаксического анализа.Это также послужит основой для сценариев.

  2. Сценарий, который выводит данные для текущей оболочки.Он может посмотреть на $ENV{SHELL}, чтобы узнать, какая оболочка работает.Для получения бонусных баллов предоставьте переключатель для явного переопределения.

  3. Сценарий, который можно вызывать внутри не-Perl-программы, такой как сервер непрерывной интеграции, и выдавать машиночитаемый вывод.XML и / или JSON или что-то еще.

2 и 3 были бы просто тонкими обертками для форматирования данных, выходящих из 1.

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

Если вы не можете разделить 2 и 3, попросите сервер непрерывной интеграции установить переменную среды и найти ее.

1 голос
/ 17 декабря 2011

Если вы используете PowerShell 2.0 или выше (скорее всего), вы можете сделать оболочку родительским процессом, изучив переменную среды %psmodulepath%.По умолчанию он указывает на системные модули в %windir%\system32\windowspowershell\v1.0\modules;это то, что вы увидите, если изучите переменную из cmd.exe.

. Однако, когда PowerShell запускается, он добавляет путь поиска модуля пользователя по умолчанию к этой переменной среды, которая выглядит так: %userprofile%\documents\windowspowershell\modules.Это наследуется дочерними процессами.Итак, ваша логика будет состоять в том, чтобы проверить, начинается ли% psmodulepath% с% userprofile%, чтобы обнаружить powershell 2.0 или выше.Это не будет работать в PowerShell 1.0, потому что он не поддерживает модули.

1 голос
/ 17 декабря 2011

Это на Windows XP с PowerShell v2.0, так что возьмите его с крошкой соли.

В cmd.exe оболочке я получаю:

PSModulePath=C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\

тогда как в окне консоли PowerShell я получаю:

PSModulePath=E:\Home\user\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsP owerShell\v1.0\Modules\

где E:\Home\user, где находится папка "Мои документы". Таким образом, одна эвристика может заключаться в проверке, содержит ли PSModulePath путь, зависящий от пользователя.

Кроме того, в окне консоли я получаю:

!::=::\

в окружающей среде. Из PowerShell ISE я получаю:

!::=::\
!C:=C:\Documents and Settings\user
1 голос
/ 16 декабря 2011

В зависимости от среды, вы можете выбрать ее из переменных среды.Рассмотрим следующий код:

/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);' | grep sh

В моей системе Ubuntu он меня получает:

'SHELL' => '/bin/bash',

Так что я предполагаю, что это говорит о том, что я запускаю perl из оболочки bash.Если вы используете что-то еще, переменная SHELL может дать вам подсказку.

Но допустим, вы знаете, что находитесь в bash, но perl запускается из подоболочки.Затем попробуйте:

/bin/sh -c "/usr/bin/perl -MData::Dumper -e 'print Dumper(\%ENV);'" | grep sh

Вы найдете:

      '_' => '/bin/sh',
      'SHELL' => '/bin/bash',

Итак, оболочка все еще bash, но в bash есть переменная $_, которая также показывает абсолютное имя файла оболочки илисценарий выполняется, что также может дать ценную подсказку.Аналогичным образом, для других сред, скорее всего, в хеше perl %ENV останутся подсказки, которые должны дать вам ценные подсказки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...