Linux 管道输出到 bash 函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11454343/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pipe output to bash function
提问by jliu83
I have as simple function in a bash script and I would like to pipe stdout to it as an input.
我在 bash 脚本中有一个简单的函数,我想通过管道将标准输出作为输入。
jc_hms(){
printf ""
}
I'd like to use it in this manner.
我想以这种方式使用它。
var=`echo "teststring" | jc_hms`
Of course I used redundant functions echo and printf to simplify the question, but you get the idea. Right now I get a "not found" error, which I assume means my parameter delimiting is wrong (the "$1" part). Any suggestions?
当然,我使用了冗余函数 echo 和 printf 来简化问题,但您明白了。现在我收到一个“未找到”错误,我认为这意味着我的参数分隔错误(“$1”部分)。有什么建议?
Originally the jc_hms function was used like this:
最初 jc_hms 函数是这样使用的:
echo `jc_hms "teststring"` > //dev/tts/0
but I'd like to store the results in a variable for further processing first, before sending it to the serial port.
但我想先将结果存储在一个变量中以供进一步处理,然后再将其发送到串行端口。
EDIT: So to clarify, I am NOT trying to print stuff to the serial port, I'd like to interface to my bash functions should the "|" pipe character, and I am wondering if this is possible.
编辑:所以澄清一下,我不是试图将内容打印到串行端口,如果“|”,我想连接到我的 bash 函数 管道字符,我想知道这是否可能。
EDIT: Alright, here's the full function.
编辑:好的,这是完整的功能。
jc_hms(){
hr=$(( / 3600))
min=$(( / 60))
sec=$(( % 60))
printf "$hs:%02d:%02d" $min $sec
}
I'm using the function to form a string which come this line of code
我正在使用该函数形成一个字符串,该字符串来自这行代码
songplaytime=`echo $songtime | awk '{print S1 }'`
printstring="`jc_hms $songplaytime`" #store resulting string in printstring
Where $songtime is a string expressed as "playtime totaltime" delimited by a space.
其中 $songtime 是一个字符串,表示为由空格分隔的“播放时间总时间”。
I wish I can just do this in one line, and pipe it after the awk
我希望我可以在一行中完成此操作,并在 awk 之后通过管道传输
printstring=`echo $songtime | awk '{print S1 }' | jc_hms`
like so.
像这样。
采纳答案by chepner
To answer your actual question, when a shell function is on the receiving end of a pipe, standard input is read by the first command executed inside the function. Since printf
is the first and only command in your function, standard input is ignored. There are several ways around that, including using the read
built-in to read standard input into a variable which can be passed to printf
:
为了回答您的实际问题,当 shell 函数位于管道的接收端时,标准输入由函数内部执行的第一个命令读取。由于printf
是函数中的第一个也是唯一的命令,因此忽略标准输入。有几种方法可以解决这个问题,包括使用read
内置将标准输入读入可以传递给的变量printf
:
jc_hms () {
read foo
hr=$(($foo / 3600))
min=$(($foo / 60))
sec=$(($foo % 60))
printf "%d:%02d:%02d" "$hr" "$min" "$sec"
}
However, since your need for a pipeline seems to depend on your perceived need to use awk
, let me suggest the following alternative:
但是,由于您对管道的需求似乎取决于您对使用的感知需求awk
,让我建议以下替代方案:
printstring=$( jc_hms $songtime )
Since songtime
consists of a space-separated pair of numbers, the shell performs word-splitting on the value of songtime
, and jc_hms
sees two separate parameters. This requires no change in the definition of jc_hms
, and no need to pipe anything into it via standard input.
由于songtime
由一对空格分隔的数字组成,shell 对 的值执行分词songtime
,并jc_hms
看到两个单独的参数。这不需要更改 的定义jc_hms
,也不需要通过标准输入将任何内容通过管道传输到其中。
If you still have a different reason for jc_hms
to read standard input, please let us know.
如果您还有其他原因jc_hms
需要阅读标准输入,请告诉我们。
回答by moopet
You can't pipe stuff directly to a bash function like that, however you can use read
to pull it in instead:
你不能像这样直接将东西通过管道传递到 bash 函数,但是你可以用read
它来代替:
jc_hms(){
while read data; do
printf "%s" "$data"
done
}
should be what you want
应该是你想要的
回答by Jo So
Or, you can also do it in a simple way.
或者,您也可以通过简单的方式来完成。
jc_hms() {
cat
}
Though all answers so far have disregarded the fact that this was not what OP wanted (he stated the function is simplified)
尽管到目前为止所有的答案都忽略了这不是 OP 想要的这一事实(他说函数被简化了)
回答by Medievalist
Hmmmm....
嗯……
songplaytime=`echo $songtime | awk '{print S1 }'`
printstring="`jc_hms $songplaytime`" #store resulting string in printstring
if you're calling awk anyway, why not use it?
如果您无论如何都在调用 awk,为什么不使用它呢?
printstring=`TZ=UTC gawk -vT=$songplaytime 'BEGIN{print strftime("%T",T)}'`
I'm assuming you're using Gnu's Awk, which is the best one and also free; this will work in common linux distros which aren't necessarily using the most recent gawk. The most recent versions of gawk will let you specify UTC as a third parameter to the strftime() function.
我假设您正在使用 Gnu 的 Awk,它是最好的,也是免费的;这将适用于不一定使用最新 gawk 的常见 linux 发行版。最新版本的 gawk 允许您指定 UTC 作为 strftime() 函数的第三个参数。
回答by user.friendly
1) I know this is a pretty old post
1)我知道这是一个很老的帖子
2) I like most of the answers here
2)我喜欢这里的大部分答案
However, I found this post because I needed to something similar. While everyone agrees stdin is what needs to be used, what the answers here are missing is the actual usage of the /dev/stdin file.
但是,我找到了这篇文章,因为我需要类似的东西。虽然每个人都同意 stdin 是需要使用的,但这里缺少的答案是 /dev/stdin 文件的实际用法。
Using the read builtin forces this function to be used with piped input, so it can no longer be used in a typical way. I think utilizing /dev/stdin is a superior way of solving this problem, so I wanted to add my 2 cents for completeness.
使用 read 内置函数强制此函数与管道输入一起使用,因此它不能再以典型方式使用。我认为使用 /dev/stdin 是解决这个问题的一种很好的方法,所以我想加上我的 2 美分以确保完整性。
My solution:
我的解决方案:
jc_hms() {
declare -i i=${1:-$(</dev/stdin)};
declare hr=$(($i/3600)) min=$(($i/60%60)) sec=$(($i%60));
printf "%02d:%02d:%02d\n" $hr $min $sec;
}
In action:
在行动:
user@hostname:pwd$ jc_hms 7800
02:10:00
user@hostname:pwd$ echo 7800 | jc_hms
02:10:00
I hope this may help someone.
我希望这可以帮助某人。
Happy hacking!
快乐黑客!
回答by Der Schley
I like user.friendly's answer using the Bash
built-in conditional unset substitution syntax.
Here's a slight tweak to make his answer more generic, such as for cases with an indeterminate parameter count:
我喜欢 user.friendly 使用Bash
内置条件未设置替换语法的答案。这是一个轻微的调整,使他的答案更通用,例如对于参数计数不确定的情况:
function myfunc() {
declare MY_INPUT=${*:-$(</dev/stdin)}
for PARAM in $MY_INPUT; do
# do what needs to be done on each input value
done
}
回答by Farway
The proposed solutions require content on stdin
or read
to be only conditionally called. Otherwise the function will wait for content from the console and require an Enteror Ctrl+Dbefore continuing.
提议的解决方案需要内容stdin
或read
仅被有条件地调用。否则,该函数将等待来自控制台的内容并在继续之前需要一个Enter或Ctrl+ D。
A workaround is to use read
with a timeout. e.g. read -t <seconds>
解决方法是使用read
超时。例如read -t <seconds>
function test ()
{
# ...
# process any parameters
# ...
read -t 0.001 piped
if [[ "${piped:-}" ]]; then
echo $piped
fi
}
Note, -t 0
did not work for me.
You might have to use a different value for the time-out.
Too small a value might result in bugs and a too large time-out delays the script.
请注意,-t 0
对我不起作用。
您可能必须使用不同的超时值。太小的值可能会导致错误,而太大的超时会延迟脚本。