如何检查我的函数是否是通过管道的输入调用的?

如何检查我的函数是否是通过管道的输入调用的?

我通常用来if [ -t 0 ]测试 stdin 并if [ -t 1 ]查看 stdin 和 stdout 是否是 TTY,如果不是,我假设它们是管道。我最近了解到这是一个错误的假设:

function context()
{
    if [ -t 0 ]
    then
        if [ -t 1 ]
        then
            echo "no pipes"
        else
            echo "pipe out only"
        fi
    else
        if [ -t 1 ]
        then
            echo "pipe in only"
        else
            echo "pipe in and out"
        fi
    fi
}

echo "No Loop:"        # these cases work as desired
context
echo 'f' | context
echo 'f' | context | cat
context | cat

echo
echo "Loop:"
echo $'foo
bar' | while read x
do
    context             # I want this to say "no pipes"
    echo 'f' | context
done

上面 bash 的输出是这样的:

No Loop:
no pipes
pipe in only
pipe in and out
pipe out only

Loop:
pipe in only
pipe in only
pipe in only
pipe in only

如何更改contextto 的定义,以便第 5 个和第 7 个调用打印“无管道”?

也就是说,我不想测试 stdin 是否不是终端(这会导致问题),而是想测试此特定函数的 stdin 是否恰好是管道。我看到它-p会检查它是否是命名管道,但我希望将其用于匿名管道。

编辑

实际用例涉及我们将调用的函数theDb来代替context.理想情况下,无论上下文如何,以下两种情况都是等效的:

cat file_with_some_sql | theDb
theDb "sql goes here"

答案1

原因“仅通过管道输入”出现四次实际上是因为该context函数工作正常,并且echo $'foo bar' | while read x ETC。是一根管子——一切循环中while正在从管道获取输入。要获得所需的输出,请将while循环更改为for循环,并且不要将任何内容通过管道传输到该for循环:

for x in foo bar; do  context ;  echo 'f' | context; done

输出:

no pipes
pipe in only
no pipes
pipe in only

要显示 OP 代码出错的地方,只需将一些内容输入到for循环中,然后看看会发生什么:

echo | for x in foo bar; do  context ;  echo 'f' | context; done

输出:

pipe in only
pipe in only
pipe in only
pipe in only

新手可能(错误地)认为while read x消耗了所有标准输入,但事实并非如此。考虑这个例子,有一个read内部while循环:

printf '%s\n' foo bar baz buzz | 
while read x; do echo $x; read y; echo ${y^^} ;done

输出:

foo
BAR
baz
BUZZ

相关内容