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

dav*_*veg 0 perl csh

RHEL6

我有一个运行perl脚本的c-shell脚本。在将大量的东西转储到stdout之后,它确定perl脚本完成时父shell应当安装到的目录(目录)。但这是一个字符串,而不是一个整数,这就是我可以通过“ exit()”返回的全部。

现在,将dir的名称存储在c-shell脚本可以读取的文件中。它有效,但不优雅。有一个更好的方法吗 ?也许我可以与perl脚本共享一些内存?

zdi*_*dim 5

短:  

  • 重定向Perl的流并最终还原以打印该信息,由shell脚本获取

  • 或者,打印最后的内容,shell脚本可以将输出传递到控制台并获取最后一行

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


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

#!/bin/csh
set DIR `perl -e'print "dir_name"'`
Run Code Online (Sandbox Code Playgroud)

而在 bash

#!/bin/bash    
DIR="$(perl -e'print "dir_name"')"
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

该问题明确提到,csh因此在下面给出。但是我必须重复一个古老的事实,那就是shell脚本bash比in 脚本好得多csh。我强烈建议您重新考虑。

重击

如果您需要程序在控制台上的输出,请逐行打印

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

或者,如果脚本完成之前不需要控制台上的输出

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

或者,为该特定打印使用文件描述符

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"
Run Code Online (Sandbox Code Playgroud)

我无法让它与单个文件描述符同时用于读取和写入(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"
Run Code Online (Sandbox Code Playgroud)

或先提取最后一行,然后打印整个输出

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

或使用命名管道

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"
Run Code Online (Sandbox Code Playgroud)

由于FIFO阻塞直到写入读取,所以Perl命令在后台。因此,如果shell脚本等待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 
& )
Run Code Online (Sandbox Code Playgroud)

(为了方便阅读而将行中断)