我通常用来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
如何更改context
to 的定义,以便第 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