将shell代码移动到函数会导致它停止运行:"没有这样的文件或目录"

时间:2015-11-28 16:37:08

标签: bash shell parameter-passing

我正在编写我的第一个bash脚本,用于分析具有不同正则表达式的文本文档。以下命令完全符合它应该做的事情:

egrep "\\i(\[.*\])?" "$1" | cut -d "{" -f2 | cut -d "}" -f1

我决定将此命令移动到一个函数,因为我需要多次执行它。问题是:我得到一个" egrep:没有这样的文件或目录" -Error在函数内部时出现错误。这是代码:

function printThis() {
  egrep "\\i(\[.*\])?" "$1" | cut -d "{" -f2 | cut -d "}" -f1
}
...
printThis

我确定我犯了一个完整的初学者错误,但我似乎无法找到它。我还替换了我的代码,所以它以cat命令开头。在这种情况下,我得到了与" cat:..."

相同的错误

感谢您的时间。

1 个答案:

答案 0 :(得分:1)

您在没有参数的情况下调用printThis(),但它期望一个($1 - 实际上,您将传递给空字符串作为egrep的文件名,这就是它抱怨的内容。

更新:事实证明,OP错误的假设是函数会看到相同的位置参数($1$2,... 。)作为封闭的脚本范围。
相反,必须将参数传递给显式 ;例如,传递第一个参数:printThis "$1";使用"$@"通过传递所有参数。

本答案的其余部分涉及如何在函数内检查强制参数。

  • 如果您希望printThis()使用 stdin 输入,只需删除"$1"grep默认会从stdin获取输入(但会如果给出至少1个文件名操作数,则忽略stdin输入。

  • 如果您确实要传递文件名操作数:强制执行的一种简单方法是传递一个是{{1构造,退出整个shell - 而不仅仅是函数! - 如果${1:?<errMsg>}丢失或为空,则显示给定的错误消息和退出代码1; e.g:

$1

注意:虽然上述使用有意义的错误消息强制存在参数值的方法很方便,但由于以下几个原因这很棘手:

  • 它终止整个shell,而不仅仅是函数,因此来自同一个shell的调用者没有机会处理错误。
  • 必须注意不要将构造放在子shell 中,因为只有子shell终止,并继续执行;例如,
    function printThis() { : "${1:?$FUNCNAME: ERROR: Please specify a filename.}" egrep "\\i(\[.*\])?" "$1" | cut -d "{" -f2 | cut -d "}" -f1 } # ... # Calling `printThis` without a filename now aborts the script and # reports "... printThis: ERROR: Please specify a filename." printThis 只会终止cat -n "${1:?missing file}" | ...运行的子shell,而不是当前shell(默认情况下,所有管道段都在自己的子shell中运行)。这就是为什么上面的代码使用cat null utility作为自己的语句来检查参数的原因。
  • 打印的错误消息总是包含一个可能分散注意力的序言,说明脚本的完整文件名和违规行号,例如:

因此,更好 - 尽管更详细 - 的方法是使用显式检查:

/Users/jdoe/scripts/foo: line 7: