使用Bash管道调用Bash函数

3

为了将内容导入Bash函数,我写了以下代码:

example () {
    if [ -z ${1+x} ]; then local S=${@:-$(</dev/stdin)}; else local S="$1"; fi
    #echo "$S"
    echo "$S" | tr ' ' '_'
}
echo 'Moizès Júnior' | example
example 'Moizès Júnior'

Moizès_Júnior
Moizès_Júnior

然而,在另一个情境下,我收到了正确的输出以及这个错误信息:"Segmentation fault (core dumped)"。

为了调试它,我想知道我在函数内部获取STDIN的方式是否有问题。

非常感谢。


请问,我在哪里使用 file <core-dump-file> - Roger
你可以在终端中输入以下命令,将 <core-dump-file> 替换为你所发布的错误信息中应该被创建的核心文件名。:-) 它可能是 bash.core 或者只是 core 或其他名称。尝试运行 ls -lt | head 命令来查看最近在当前目录下创建的文件。 - ghoti
除了脚本输出之外,我收到的唯一消息是“分段错误(核心已转储)”。在“ls -lt | head”之后,我注意不到任何异常。 - Roger
1
FYI -- local var=$(something) 实际上是一种反模式,因为它具有 local 的退出状态(始终成功),而不是 something 的退出状态。更好的方法是 local var; var=$(something) - Charles Duffy
1
另外,仅查看$1是否为空有点奇怪,但是却将所有的$@连接起来(在这种情况下,将其分配给字符串并不是定义行为--顺便说一下,使用$*代替)。如果您想查看是否有任何参数,请查看$#--否则,example '' "hello"将尝试从stdin读取。 - Charles Duffy
显示剩余2条评论
2个回答

2

我建议不要将整个stdin读入变量中。而是使用以下方法:

#the main "worker" function always uses stdin/out
example_worker() { tr ' ' '_'; }

#the switcher
example() { if [[ -z "$1" ]]; then example_worker; else example_worker <<< "$1"; fi ; }

echo 'a b c' | example
example 'a b c'
#but also
example < multi_giga_file.txt

想象一下,我有许多函数,比如“example_worker1”,“example_worker2”,“example_worker3”,“example_worker4”……所有这些函数都与你的“example_worker”具有相似的行为。@jm666,你会如何处理? - Roger
@Roger,你想要实现什么并不清楚。是想按顺序调用多个工作线程(类似管道)还是根据某些条件一次只调用一个?在寻求帮助时需要表述清楚。这个问题已经有了答案,所以最好提出一个新问题,并给出更精确的情况描述。此外,你的示例代码并没有尝试调用“多个”工作线程... - clt60

1
如果 bash 负责核心转储,那肯定表明 bash 中存在应该报告的错误。然而,您的函数可以更简单地编写为:
example () {
    local S
    if (( "$#" == 0 )); then
        IFS= read -r S
        set -- "$S"
    fi
    echo "${1// /_}"
}

这至少可以避免bug。


为什么你说这样更简单(去掉tr ' ' '_'部分,这只是一个例子,可以是其他任何东西)?你的代码更高效吗?我觉得它更难理解,特别是set -- "$S"部分。 - Roger
它为什么不起作用,或者你是在尝试使用 example Moizès Júnior 而不是 example "Moizès Júnior" - chepner
我的意思是 例子 'Moizès Júnior' - Roger
1
@Roger,“set --“$S””将$1设置为等于“$S”。只是因为某些东西是不熟悉的,这并不意味着它们是复杂的。(附注:Rich Hickey的演讲,“Simple Made Easy”,非常好地分离了所有这些概念,帮助人们将它们分开考虑...一个过程,他会建议使用“decomplecting”这个词来描述它)。 - Charles Duffy
2
@chepner,...我可能会在这里做的唯一更改是IFS= read -r -d'' S || [[ $S ]]或类似的东西,以便能够读取多行字符串。 - Charles Duffy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接