Linux 编写同时接受管道输入和参数的Shell函数

Linux 编写同时接受管道输入和参数的Shell函数,linux,function,pipe,stdin,ksh,Linux,Function,Pipe,Stdin,Ksh,我正在尝试编写一个调用logAction的函数,专门用于Ksh从管道读取输入并在同一个函数调用中接受参数。我在谷歌和类似的网站上搜索了两周,试图调试这个 我试图创建的函数的目的是简化将输出记录到我开发的其他脚本的日志文件的过程。我打算在各种情况下使用该命令,但最容易描述和说明我正在尝试的两种情况与以下类似: 语法示例1: logAction 1 "Script executed some action." 语法示例2: COMMAND1 | COMMAND2 | logAction 1 如您

我正在尝试编写一个调用
logAction
的函数,专门用于
Ksh
从管道读取输入并在同一个函数调用中接受参数。我在谷歌和类似的网站上搜索了两周,试图调试这个

我试图创建的函数的目的是简化将输出记录到我开发的其他脚本的日志文件的过程。我打算在各种情况下使用该命令,但最容易描述和说明我正在尝试的两种情况与以下类似:

语法示例1:

logAction 1 "Script executed some action."
语法示例2:

COMMAND1 | COMMAND2 | logAction 1
如您所见,我希望能够通过管道将预期的日志信息作为参数或stdinput传递给函数,以便捕获命令序列的输出。第三种情况是在管道输出之前预加一些文本,即

语法示例3:

COMMAND1 | COMMAND2 | logAction 1 "This is the output:  "
[2015/12/28 10:20:32] This is the output:  <Output from COMMAND1 | COMMAND 2>
下面的输出说明了使用示例3中的语法会得到什么结果:

COMMAND1 | COMMAND2 | logAction 1 "This is the output:  "
[2015/12/28 10:20:32] This is the output:  <Output from COMMAND1 | COMMAND 2>
最初,我没有为
read
命令提供
-t
参数,函数将暂停执行,直到用户输入
CTRL-D
以指示
EOF
。但是,出于我的目的,此函数旨在进行静默操作,不应请求用户输入。用
read
命令添加
-t0
参数会告诉read命令超时0秒,而不是等待键盘发出
EOF

这就解决了某些情况下的问题;但是,与
cat
命令一起使用时,
read
命令不会捕获任何输入,如下所示:

cat somefile.txt | logAction 1
cat somefile.txt | awk '{ a=a" "$1 }END{ print a }' | logAction 1
然而,使用echo似乎是可行的:

echo "ab bc cd de ef fg gh" | logAction 1 "This is the output: "
通过将超时的0更改为0.1(即
read-t0.1
),我已经能够使它与
cat
一起工作,但我担心这是一个肮脏的解决方案。这似乎表明存在争用条件,即在管道完成输出并关闭之前执行
read
命令。这不是我所期望的,因为我认为管道序列中的前一个命令必须在执行后续命令之前完成执行

有没有办法告诉
read
命令忽略键盘上的stdin并使用管道中前面命令中的stdout?我试图告诉它使用
FD0
(我认为这是来自管道的标准输出,但它似乎也连接到了键盘)和
-u0
参数,但这似乎不起作用。

试试这个:

#!/bin/ksh

function log 
{
    ARG1=$1
    ARG2=$2

    if [ ! -t 0 ] 
    then
        INPUT=$(cat)
    else
        INPUT=""
    fi  

    echo "<datetime>" ${ARG2}${INPUT}
}

log 1 "Script executed some action."

echo "<data from pipe>" | log 2 "this is the output: "

echo "<data from pipe>" | cat | log 2 "this is the output: "
#/bin/ksh
功能日志
{
ARG1=$1
ARG2=2美元
if[!-t0]
然后
输入=$(cat)
其他的
INPUT=“”
fi
回显“${ARG2}${INPUT}”
}
日志1“脚本执行了一些操作。”
echo“| log 2”这是输出:
echo“| cat | log 2”这是输出:
输出:

<datetime> Script executed some action.
<datetime> this is the output: <data from pipe>
<datetime> this is the output: <data from pipe>
脚本执行了一些操作。
这是输出:
这是输出:
试试这个:

#!/bin/ksh

function log 
{
    ARG1=$1
    ARG2=$2

    if [ ! -t 0 ] 
    then
        INPUT=$(cat)
    else
        INPUT=""
    fi  

    echo "<datetime>" ${ARG2}${INPUT}
}

log 1 "Script executed some action."

echo "<data from pipe>" | log 2 "this is the output: "

echo "<data from pipe>" | cat | log 2 "this is the output: "
#/bin/ksh
功能日志
{
ARG1=$1
ARG2=2美元
if[!-t0]
然后
输入=$(cat)
其他的
INPUT=“”
fi
回显“${ARG2}${INPUT}”
}
日志1“脚本执行了一些操作。”
echo“| log 2”这是输出:
echo“| cat | log 2”这是输出:
输出:

<datetime> Script executed some action.
<datetime> this is the output: <data from pipe>
<datetime> this is the output: <data from pipe>
脚本执行了一些操作。
这是输出:
这是输出:

感谢您的回答@Ziffusion。这似乎奏效了。在使用
cat
之前,我遇到过这个技巧;然而,我没有使用它,因为我想我在某个地方读到它可能会遇到竞争条件或有其他漏洞。与使用
cat
的这种伎俩相比,该函数似乎更适合使用内置命令。尽管如此,我还是用我的代码对它进行了测试,现在它似乎可以工作了。我仍然很好奇为什么
read
在我的示例中不起作用。shell是如何在管道中先前的命令完成执行之前执行
read
timeout参数的?这就是它应该如何工作的。
0
超时会导致
read
立即返回。我理解
0
超时会导致
read
立即返回;但是,我认为这只会在管道中的前一个命令完成并且输出被馈送到包含
read
的函数调用时发生。如果我错了,请纠正我的错误,但是如果我构造了一个类似于
CMD1 | CMD2 | MyFunction
的管道,该函数不是只有在CMD2完成后才执行吗?CMD2的输出是否应该立即可用于函数,以便
MyFunction
中的
read
命令的
0
超时仍然捕获输入?
CMD1
CMD2
MyFunction
shell
在其自己的
进程中并行执行。它们几乎同时开始执行。您的名字
MyFunction
有点用词不当,因为您运行它的方式是一个
进程
。尽管如此,shell脚本可以包含函数(就像我的代码一样)。感谢您的澄清!我想我假设这些命令是按顺序执行的,因为它们似乎依赖于以前命令的输出,但我可以理解如何设置管道,并且进程将保持并行并处理任何输出,直到管道被以前的命令关闭。感谢您的回答@Ziffusion。这似乎奏效了。在使用
cat
之前,我遇到过这个技巧;然而,我没有使用它,因为我想我在某个地方读到它可能会遇到竞争条件或有其他漏洞。与使用
cat
的这种伎俩相比,该函数似乎更适合使用内置命令。