我可以将perl中的字符串传递回调用c-shell吗?

时间:2018-05-24 22:12:51

标签: perl csh

RHEL6

我有一个运行perl脚本的c-shell脚本。在将大量内容转储到stdout之后,它确定了当perl脚本完成时父shell应该cd到哪里(什么dir)。但这是一个字符串,而不是一个int,这是我可以用“exit()”传回来的。

将dir的名称存储在c-shell脚本可以读取的文件中,这就是我现在所拥有的。它有效,但不优雅。有一个更好的方法吗 ?也许我可以用perl脚本分享一小块内存?

1 个答案:

答案 0 :(得分:4)

简短:

  • 重定向Perl的流并在最后恢复以打印由shell脚本获取的信息

  • 或者,打印 last 并且shell脚本可以将输出传递给控制台并采取最后一行

  • 或者,对该打印使用命名管道(shell)或特定文件描述符(不是csh

当Perl脚本打印出该名称时,您可以将其分配给变量 在shell脚本中

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

中的

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

其中$(...)是命令替换的首选。

但是需要处理从Perl脚本到控制台的其他打印件

  • 一种方法是重定向Perl脚本中除一个打印之外的所有输出,可以通过命令行选项控制(可以重定向的文件名,可以打印出哪个shell脚本)
  • 或者,取所有Perl的输出并将其传递给控制台,最后一行是所需的“返回”。这使得Perl脚本的负担最后打印(可能在END块中)。程序的输出可以在shell脚本完成后打印,也可以在发出时逐行打印。

  • 或者,使用命名管道(两个shell)或特定文件描述符(仅bash),Perl脚本可以将该信息打印到该文件。在这种情况下,它的流直接进入控制台。

问题明确提到csh所以它在下面给出。但是我必须重复一个陈旧的事实,即bash中的shell脚本编写要比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状态,直到写入读取为止。因此,如果shell脚本要等待perl ...完成,那么Perl脚本会在写入FIFO时阻塞(因为它没有被读取)所以shell永远不会读取它;我们会陷入僵局。它也在子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 
& )

(为了便于阅读而划清界限)