在Bash中参数化对应用程序的链接调用


12

我在Bash shell中使用了一个黑匣子UNIX程序,该程序从stdin读取数据列,对其进行处理(应用平滑效果),然后输出到stdout。我通过UNIX管道使用它,例如

generate | smooth | plot  

为了更加平滑,我可以重复进行平滑操作,因此可以从Bash命令行中调用它,如下所示:

generate | smooth | smooth | plot   

甚至

generate | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | plot

这变得越来越古怪。我想制作一个Bash包装器,使其能够通过管道传递smooth并将其输出直接反馈到smooth任意次数的新实例中,例如

generate | newsmooth 5 | plot

代替

generate | smooth | smooth | smooth | smooth | smooth | plot

我的第一次尝试是一个Bash脚本,该脚本在当前目录中生成了临时文件并删除了它们,但是当我不在具有写访问权限的目录中时,它变得很丑陋,并且在被中断时还留下了垃圾文件。

smooth程序没有参数。

有没有更优雅的方式来“包装”这样的程序来参数化调用次数?


1
我希望您的示例出于问题而不是实际需要成为强制案例
arielnmz

Answers:


18

您可以将其包装在一个递归函数中:

smooth() {
  if [[ $1 -gt 1 ]]; then # add another call to function
    command smooth | smooth $(($1 - 1)) 
  else
    command smooth # no further 
  fi
}

您可以将其用作

generate | smooth 5 | plot

相当于

generate | smooth | smooth | smooth | smooth | smooth | plot

这是完美的,完全按照需要运行。现在,我了解了bash的“ command”关键字。
黛安·威尔博

2
顺便说一句,这与我如何编码任意长的管道链中使用的方法相同-并且,在此之前,处理xmlstarlet中的长编辑列表
查尔斯·达菲

5

如果您负担得起键入所需数量的逗号,则smooth可以利用Shell逗号分隔的Brace Expansion。

TL; 博士

您的示例案例的整个命令行为:

generate | eval 'smooth |'{,,,,} plot

注意:

  • 如果要重复更多或更少的重复,请添加或删除逗号 smooth |
  • |之前没有,plot因为它包含在smooth |Brace Expansion生成的最后一个字符串中
  • 您还可以提供的参数smooth,只要您可以将它们正确地包含在带括号的加引号的固定部分中;无论如何,请记住,您将为命令的所有重复提供它们

怎么运行的

逗号分隔的括号扩展允许您动态生成字符串,每个字符串都由指定的固定部分和指定的可变部分组成。它产生的字符串与所指示的可变部分一样多,例如a{b,c,d}Produces ab ac ad

这里的一个小窍门是,如果您宁愿列出一个空的可变部分的列表,即在括号中仅包含逗号,则“括号扩展”将仅生成固定部分的副本。例如:

smooth{,,,,}

将产生:

smooth smooth smooth smooth smooth

请注意,四个逗号产生5个smooth字符串。这就是Brace Expansion的工作方式:它产生的字符串与逗号加一个一样多。

当然,在您的情况下,您还需要将它们|分开smooth,因此只需将其添加到固定部分中,但要小心地引用它,以使Shell 不会立即对其进行解释。那是:

'smooth|'{,,,,}

将产生:

'smooth|' 'smooth|' 'smooth|' 'smooth|' 'smooth|'

就拿始终把固定部分护理立即靠近开括号,即在之间没有空格' 和{

(还请注意,要形成固定部分,如果需要在固定部分中扩展外壳变量,也可以使用双引号而不是单引号。只需注意出现某些外壳特殊字符时所需的额外转义在双引号字符串中)。

在这一点上,您需要将其eval 应用于该字符串,以使Shell最终将其解释为它应该是的管道命令。

因此,总而言之,您的示例案例的整个命令行将是:

generate | eval 'smooth |'{,,,,} plot

1
如果将其用于参数化调用的地方,则存在重大的安全问题。请参阅我关于递归bash函数与迭代“ eval”字符串构建的答案:哪个执行得更好?在堆栈溢出上结束。
查尔斯·达菲

1
@CharlesDuffy我完全同意您对使用隐式风险的担心,eval当它提供不可信,未经卫生处理的字符串供其评估时,即与可能包含“未知”内容的变量一起使用时(如您所链接的情况),该隐式风险会引起您的担忧。另一方面,eval对于快速“插入”命令也非常方便,尤其是在提示符下使用时,例如手头的情况似乎是,其中eval的输入只能是用户手动输入的文字字符串。人
LL3

正如在其他地方已经看到的那样,您总是可以eval str用自负和愚蠢的东西代替. /dev/stdin <<<str。这不仅会给愚人留下深刻的印象,还会使@CharlesDuffy远离您的后备;-)
pizdelect

1
@pizdelect,您可能会仔细阅读LL3的先前评论-平衡,细腻且明智。(实际上,我自己的初始注释中有细微差别,您似乎会忽略;“如果在参数化调用的情况下使用”,则是一个关键的区别:LL3的实例参数化,因此很安全)。
Charles Duffy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.