Могу ли я передать строку из Perl обратно в вызывающую c-shell? - PullRequest
0 голосов
/ 25 мая 2018

RHEL6

У меня есть скрипт c-shell, который запускает скрипт perl.После выгрузки тонны материала в stdout, он определяет, куда (в какой каталог) следует обратиться родительской оболочке, когда завершится сценарий perl.Но это строка, а не int, это все, что я могу передать с помощью «exit ()».

Сохранение имени каталога в файле, который может прочитать скрипт c-shell, - это то, что я сейчас имею.Это работает, но не элегантно.Есть лучший способ сделать это ?Может быть, небольшой кусок памяти, которым я могу поделиться со скриптом Perl?

1 Ответ

0 голосов
/ 25 мая 2018

Short:

  • Перенаправить потоки Perl и восстановить в конце, чтобы напечатать эту информацию, взятую сценарием оболочки

  • Или выведите, что last и сценарий оболочки может передать вывод на консоль и взять последнюю строку

  • Или использовать именованный канал (либо оболочка) или конкретные файловые дескрипторы (не csh) для этой печати


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

#!/bin/csh
set DIR `perl -e'print "dir_name"'`

в то время как в bash

#!/bin/bash    
DIR="$(perl -e'print "dir_name"')"

, где $(...) предпочтительнее для подстановки команд.

Но тогда эти другие распечатки на консоль из сценария Perl должныбыть обработанным

  • Одним из способов является перенаправление всех выходных данных в скрипте Perl, кроме той одной печати, что может управляться параметром командной строки (имя файла, куда перенаправлять, какой скрипт оболочки может распечатать)
  • Или, возьмите весь вывод Perl и передайте его на консоль,Астлайн - это необходимое «возвращение».Это накладывает бремя на скрипт Perl для печати этого последнего (возможно, в блоке END).Вывод программы может быть распечатан из сценария оболочки после его завершения или построчно по мере ее выдачи.

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

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

bash

Если вам нужен вывод программы на консоль по ходу, возьмите и напечатайте ее построчно

#!/bin/bash    
while read line; do
    echo "$line"
    DIR=$line
done < <(perl script.pl)
echo "$DIR"

Или,если вам не нужен вывод на консоль до завершения сценария

#!/bin/bash
mapfile -t lines < <(perl script.pl)
DIR="${lines[-1]}"
printf '%s\n' "${lines[@]}"           # print script.pl's output

Или используйте файловые дескрипторы для этого конкретного отпечатка

F=$(mktemp)    # safe filename
exec 3> "$F"   # open fd 3 to write to it
exec 4< "$F"   # open fd 4 to read from it
rm -f "$F"     # remove file(name) for safety; opened fd's can still access
perl -E'$fd=shift; say "...normal prints to STDOUT..."; 
    open(FH, ">&=$fd") or die $!; 
    say FH "dirname"; 
    close FH
' 3
read dir_name <&4
exec 3>&-          # close them
exec 4<&-
echo "$dir_name"

Я не смог заставить его работатьс одним файловым дескриптором для чтения и записи (exec 3<> ...), я думаю, потому что чтение не может перематывать после записи, поэтому используются отдельные дескрипторы.

С помощью сценария Perl (а не демонстрационной однострочной строки выше) передайте номер fd в качестве параметра командной строки.Сценарий может сделать это, только если он вызывается с этой опцией.

Или используйте именованный канал очень похоже на то, как это сделано для csh ниже.Это, вероятно, лучше всего здесь, если вам не нравится манипулирование с программой STDOUT.

csh

Перебирайте выходные данные программы (выполнено) строка за строкой

#!/bin/csh
foreach line ( "`perl script.pl`" )
    echo "$line"
    set dir_name = "$line"
end
echo "Directory name: $dir_name"

или сначала извлеките последнюю строку, а затем напечатайте весь вывод

#!/bin/csh
set lines = ( "`perl script.pl`" )
set dir_name = $lines[$#]
# Print program's output
while ( $#lines )
     echo "$lines[1]"
     shift lines
 end

или используйте именованный канал

set fifo_name = "/tmp/fifo$$"  # or use mktemp
mkfifo "$fifo_name"
( perl script.pl --fifo $fifo_name [other args]  & )
set dir_name = `cat "$fifo_name"`
rm -f $fifo_name

echo "dir name from FIFO: $dir_name"

Команда Perlв фоновом режиме, поскольку блоки FIFO пока не написаны и read.Поэтому, если сценарий оболочки будет ждать завершения perl ..., сценарий Perl будет блокироваться при записи в FIFO (поскольку он не читается), поэтому shell никогда не сможет его прочитать;мы бы зашли в тупик.Он также находится в подоболочке, с ( ), чтобы избежать информационных отпечатков о фоновом задании.

Опция командной строки --fifo NAME необходима, чтобы скрипт Perl знал, какой специальный файл использовать (и не делать этого, если эта опция отсутствует).

Для встроенного примера замените ( perl script ...) на одну строчку:

( perl -E'$ff = shift; say qq(\t...normal prints to STDOUT...); 
     open FF, ">$ff" or die $!; 
     say FF "dir_name_$$"; 
     close FF
 ' $fifo_name 
& )

(разбитые строки для удобства чтения)

...