Bash 函数处理来自管道的输入

Bash 函数处理来自管道的输入,bash,shell,Bash,Shell,我正在尝试编写一个bash函数,以按其编号返回管道输出的特定行。 当前,完整命令如下所示: mdfind 'my_search_string' | sed "2q;d" 这将返回mdfind命令的第二行输出 我试图将sed“$1q;d”转换为一个被指定为别名的函数 如何处理管道输入?要返回第二行输出,请执行以下操作: ... | sed -ne 2p 并将其用作函数: function print_2nd_line { sed -ne 2p } mdfind 'my_search_

我正在尝试编写一个bash函数,以按其编号返回管道输出的特定行。 当前,完整命令如下所示:

mdfind 'my_search_string' | sed "2q;d"
这将返回mdfind命令的第二行输出

我试图将
sed“$1q;d”
转换为一个被指定为别名的函数


如何处理管道输入?

要返回第二行输出,请执行以下操作:

... | sed -ne 2p
并将其用作函数:

function print_2nd_line {
    sed -ne 2p
}

mdfind 'my_search_string' | print_2nd_line
您还可以选择较短的名称,如
p2

该功能还可以定制为能够打印指定文件的第二行,如:

function print_2nd_line {
    sed -ne 2p -- "$@"
}

print_2nd_line file
... | print_2nd_line  ## Still could be used like this.
顺便说一下,更有效的版本是

sed -ne '2{p;q}'
更新

正如Charles Duffy所建议的,您也可以使用这种格式来实现POSIX兼容性。实际上,它也与所有基于原始SystemV sh的shell兼容

print_2nd_line() {        
    sed -ne '2{p;q}' -- "$@"
}
此外,如果要将自定义行号传递给函数,可以:

print_2nd_line() {
    N=$1; shift
    sed -ne "${N}{p;q}" -- "$@"
}
您可以将其作为以下内容运行:

... | print_2nd_line 2  ## Still could be used like this.


您只需要保护变量名:

要定义名为search的函数,请执行以下操作:

search() { ... | sed -n "${1}p;q"; }
但请注意,这不是可移植的
sed
。这样做会更好

search() { ... | sed -n "${1}{p; q;}"; }
事实上,原始的sed不仅仅是不可移植的,而且不能满足您的需要!它应该总是在处理第1行之后退出。如果您有一个
sed
,它的行为与您在问题陈述中描述的一样,您可能需要再次检查

我的awked bash别名:

alias second=“awk”FNR==2'

cat文件|秒

第二个文件

所以,我不太明白,你们想写一个函数,把要过滤的行数作为参数吗?您还想处理其中的管道输入以过滤掉该行吗?管道输入将是函数的参数,您可以通过
$@
获取所有参数

对不起,我知道OP想要什么:)
当我得到它时,他希望处理带有参数的shell函数输入的
std
,即

cmd | func参数

因此,以下工作:

函数筛选{awk“FNR==1”}

例如:

cat文件|筛选2

(请参见关于
awk
vs
sed
)的注释作为练习--

此版本使用纯bash,根本不使用任何外部工具:

return_line() {
  local lineno=$1
  while (( lineno > 1 )); do read; (( lineno-- )); done
  read -r && printf '%s\n' "$REPLY"
}

# ...to test...
return_line 3 <<<$'one\ntwo\nthree\nfour'

# ...and yes, this works with pipelines...
printf 'one\ntwo\nthree\nfour' | return_line 3
返回_行(){
本地线路号=$1
当((行号>1));读;((行号-);完成
read-r&&printf“%s\n'$REPLY”
}
#…测试。。。

return_第3行只有一个诡辩--
function
关键字实际上弊大于利,破坏了POSIX兼容性,却没有带来任何好处。最好省去它:
print_2nd_line(){…}
@CharlesDuffy Yes对于POSIX兼容性,最好使用它。在Bash中,我实际上默认使用
函数
,但在其他shell中,或者当我指的是兼容性时,使用
f(){}
格式。这似乎没有响应的唯一方法是硬编码要提取的行号,当问题读作想要参数化时。使用函数比使用别名好得多——默认情况下,脚本中根本不启用别名。Awk脚本在打印后不会终止,因此对于长输入,它将比OP的
sed
脚本慢得多。这并不难解决,但有一个明显的区别,可能在翻译过程中丢失了。仅供参考,在bash中阅读输入的最佳实践已包含在内--您将在此处获得更直接相关的答案,但对于那些发现这个问题对他们来说不切题的人来说,这可能是一个有用的链接。
return_line() {
  local lineno=$1
  while (( lineno > 1 )); do read; (( lineno-- )); done
  read -r && printf '%s\n' "$REPLY"
}

# ...to test...
return_line 3 <<<$'one\ntwo\nthree\nfour'

# ...and yes, this works with pipelines...
printf 'one\ntwo\nthree\nfour' | return_line 3