bash 如何制作一个可以从标准输入读取的bash函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18761209/
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
How to make a bash function which can read from standard input?
提问by JBoy
I have some scripts that work with parameters, they work just fine but i would like them to be able to read from stdin, from a pipe for example, an example, suppose this is called read:
我有一些使用参数的脚本,它们工作得很好,但我希望它们能够从标准输入读取,例如从管道读取,例如,假设这称为读取:
#!/bin/bash
function read()
{
echo $*
}
read $*
Now this works with read "foo" "bar"
, but I would like to use it as:
现在这适用于read "foo" "bar"
,但我想将其用作:
echo "foo" | read
How do I accomplish this?
我该如何实现?
采纳答案by fedorqui 'SO stop harming'
You can use <<<
to get this behaviour. read <<< echo "text"
should make it.
您可以使用<<<
来获取此行为。read <<< echo "text"
应该做到。
Test with readly
(I prefer not using reserved words):
测试readly
(我不喜欢使用保留字):
function readly()
{
echo $*
echo "this was a test"
}
$ readly <<< echo "hello"
hello
this was a test
With pipes, based on this answer to "Bash script, read values from stdin pipe":
使用管道,基于对“Bash 脚本,从标准输入管道读取值”的回答:
$ echo "hello bye" | { read a; echo $a; echo "this was a test"; }
hello bye
this was a test
回答by chepner
It's a little tricky to write a function which can read standard input, but works properly when no standard input is given. If you simply try to read from standard input, it will block until it receives any, much like if you simply type cat
at the prompt.
编写一个可以读取标准输入但在没有给出标准输入时正常工作的函数有点棘手。如果您只是尝试从标准输入中读取,它将阻塞直到收到任何,就像您只是cat
在提示符下键入一样。
In bash 4, you can work around this by using the -t
option to read
with an argument of 0. It succeeds if there is any input available, but does not consume any of it; otherwise, it fails.
在 bash 4 中,您可以通过使用参数为 0的-t
选项来解决这个问题。read
如果有任何可用输入,它会成功,但不消耗任何输入;否则,它将失败。
Here's a simple function that works like cat
if it has anything from standard input, and echo
otherwise.
这是一个简单的函数,它的工作原理就像cat
它有来自标准输入的任何东西一样,echo
否则。
catecho () {
if read -t 0; then
cat
else
echo "$*"
fi
}
$ catecho command line arguments
command line arguments
$ echo "foo bar" | catecho
foo bar
This makes standard input take precedence over command-line arguments, i.e., echo foo | catecho bar
would output foo
. To make arguments take precedence over standard input (echo foo | catecho bar
outputs bar
), you can use the simpler function
这使得标准输入优先于命令行参数,即echo foo | catecho bar
会输出foo
。要使参数优先于标准输入(echo foo | catecho bar
输出bar
),您可以使用更简单的函数
catecho () {
if [ $# -eq 0 ]; then
cat
else
echo "$*"
fi
}
(which also has the advantage of working with anyPOSIX-compatible shell, not just certain versions of bash
).
(这也具有使用任何POSIX 兼容 shell的优点,而不仅仅是某些版本的bash
)。
回答by Andy
To combine a number of other answers into what worked for me (this contrived example turns lowercase input to uppercase):
将许多其他答案组合成对我有用的答案(这个人为的例子将小写输入转换为大写):
uppercase() {
local COMMAND='tr [:lower:] [:upper:]'
if [ -t 0 ]; then
if [ $# -gt 0 ]; then
echo "$*" | ${COMMAND}
fi
else
cat - | ${COMMAND}
fi
}
Some examples (the first has no input, and therefore no output):
一些示例(第一个没有输入,因此没有输出):
:; uppercase
:; uppercase test
TEST
:; echo test | uppercase
TEST
:; uppercase <<< test
TEST
:; uppercase < <(echo test)
TEST
Step by step:
一步步:
test if file descriptor 0 (
/dev/stdin
) was opened by a terminalif [ -t 0 ]; then
tests for CLI invocation arguments
if [ $# -gt 0 ]; then
echo all CLI arguments to command
echo "$*" | ${COMMAND}
else if
stdin
is piped (i.e. not terminal input), outputstdin
to command (cat -
andcat
are shorthand forcat /dev/stdin
)else cat - | ${COMMAND}
测试文件描述符 0 (
/dev/stdin
) 是否被终端打开if [ -t 0 ]; then
CLI 调用参数的测试
if [ $# -gt 0 ]; then
将所有 CLI 参数回显到命令
echo "$*" | ${COMMAND}
else if
stdin
是通过管道传输的(即不是终端输入),输出stdin
到命令(cat -
并且cat
是 的简写cat /dev/stdin
)else cat - | ${COMMAND}
回答by kenorb
Here is example implementation of sprintf
function in bash which uses printf
and standard input:
这是sprintf
使用printf
标准输入的bash 函数的示例实现:
sprintf() { local stdin; read -d '' -u 0 stdin; printf "$@" "$stdin"; }
Example usage:
用法示例:
$ echo bar | sprintf "foo %s"
foo bar
This would give you an idea how function can read from standard input.
这会让您了解函数如何从标准输入中读取。
回答by zwbetz
Late to the party here. Building off of @andy
's answer, here's how I define my to_uppercase
function.
这里的派对迟到了。基于@andy
的答案,这是我定义to_uppercase
函数的方式。
- if stdin is not empty, use stdin
- if stdin is empty, use args
- if args are empty, do nothing
- 如果标准输入不为空,使用标准输入
- 如果 stdin 为空,则使用 args
- 如果 args 为空,则什么都不做
to_uppercase() {
local input="$([[ -p /dev/stdin ]] && cat - || echo "$@")"
[[ -n "$input" ]] && echo "$input" | tr '[:lower:]' '[:upper:]'
}
Usages:
用法:
$ to_uppercase
$ to_uppercase abc
ABC
$ echo abc | to_uppercase
ABC
$ to_uppercase <<< echo abc
ABC
Bash version info:
Bash 版本信息:
$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
回答by DocSalvager
I've discovered that this can be done in one line using test
and awk
...
我发现这可以在一行中使用test
和awk
...
test -p /dev/stdin && awk '{print}' /dev/stdin
The test -p
tests for input on a pipe, which accepts input via stdin. Only if input is present do we want to run the awk
since otherwise it will hang indefinitely waiting for input which will never come.
在test -p
上一个管,该管通过stdin接受输入用于输入测试。只有当输入存在时,我们才想要运行,awk
否则它将无限期地挂起等待永远不会到来的输入。
I've put this into a function to make it easy to use...
我已将其放入一个函数中以使其易于使用...
inputStdin () {
test -p /dev/stdin && awk '{print}' /dev/stdin && return 0
### accepts input if any but does not hang waiting for input
#
return 1
}
Usage...
用法...
_stdin="$(inputStdin)"
Another function uses awk without the test to wait for commandline input...
另一个函数使用没有测试的 awk 来等待命令行输入......
inputCli () {
local _input=""
local _prompt=""
#
[[ "$_prompt" ]] && { printf "%s" "$_prompt" > /dev/tty; }
### no prompt at all if none supplied
#
_input="$(awk 'BEGIN {getline INPUT < "/dev/tty"; print INPUT}')"
### accept input (used in place of 'read')
### put in a BEGIN section so will only accept 1 line and exit on ENTER
### WAITS INDEFINITELY FOR INPUT
#
[[ "$_input" ]] && { printf "%s" "$_input"; return 0; }
#
return 1
}
Usage...
用法...
_userinput="$(inputCli "Prompt string: ")"
Note that the > /dev/tty
on the first printf
seems to be necessary to get the prompt to print when the function is called in a Command Substituion $(...)
.
请注意,当在 Command Substituion 中调用该函数时> /dev/tty
,第一个printf
似乎是获取提示打印所必需的$(...)
。
This use of awk
allows the elimination of the quirky read
command for collecting input from keyboard or stdin.
这种使用awk
允许消除read
从键盘或标准输入收集输入的古怪命令。