将 shell 代码移动到一个函数会导致它停止运行:"no such file or directory"
Moving shell code to a function causes it to stop functioning: "no such file or directory"
我正在编写我的第一个 bash 脚本,用于分析具有不同正则表达式的文本文档。以下命令完全按照预期执行:
egrep "\i(\[.*\])?" "" | cut -d "{" -f2 | cut -d "}" -f1
我决定将这个命令移动到一个函数中,因为我需要多次执行它。问题是:当它在函数内部时,我得到一个 "egrep : no such file or directory"-Error。这是代码:
function printThis() {
egrep "\i(\[.*\])?" "" | cut -d "{" -f2 | cut -d "}" -f1
}
...
printThis
我确定我犯了一个完全初学者的错误,但我似乎找不到它。我还替换了我的代码,因此它以 cat 命令开头。在那种情况下,我会收到以 "cat : ..."
开头的相同错误
感谢您的宝贵时间。
你在调用 printThis()
时没有参数,但它需要一个 (</code>)</strong> - 实际上,你传递的是 <em>空字符串</em>作为<code>egrep
的文件名,这就是它所抱怨的。
更新:事实证明,OP 的错误假设是函数会看到相同的位置参数(</code>、<code>
、. ..) 作为封闭脚本范围。
相反,参数必须显式传递给函数;例如,通过以下方式传递第一个参数:printThis ""
;使用"$@"
传递所有参数。
此答案的其余部分涉及如何检查函数内的强制参数。
如果您希望printThis()
使用stdin输入,只需删除""
:grep
将接受输入默认来自 stdin(但如果至少给出 1 个文件名操作数,将忽略 stdin 输入)。
如果你确实想传递一个文件名操作数:强制一个被传递的简单方法是将 shell 参数扩展与 ${1:?<errMsg>}
构造一起使用,它会退出整个 shell - 而不仅仅是函数! - 使用给定的错误消息和 1
的退出代码,如果 </code> 缺失或为空;例如:</p></li>
</ul>
<pre><code>function printThis() {
: "${1:?$FUNCNAME: ERROR: Please specify a filename.}"
egrep "\i(\[.*\])?" "" |
cut -d "{" -f2 | cut -d "}" -f1
}
# ...
# Calling `printThis` without a filename now aborts the script and
# reports "... printThis: ERROR: Please specify a filename."
printThis
注意:虽然上述强制存在带有有意义的错误消息的参数值的方法很方便,但由于以下几个原因它很棘手:
- 它终止了整个 shell,而不仅仅是函数,因此来自同一个 shell 的调用者没有机会处理错误。
- 必须注意不要将构造放在 subshell 中,因为只有 subshell 才会终止,并且执行会继续;例如,
cat -n "${1:?missing file}" | ...
只会终止 cat
运行 中的子 shell,而不是当前的 shell(默认情况下,所有管道段 运行他们自己的子shell)。这就是为什么上面的代码使用 :
、null utility 作为自己的语句来检查参数的原因。
- 打印的错误消息总是包含一个可能会分散注意力的序言,说明脚本的完整文件名和违规行号,例如
/Users/jdoe/scripts/foo: line 7:
因此,一种更好(尽管更冗长)的方法是使用显式检查:
function printThis() {
[[ -n ]] || { echo "$FUNCNAME: Please specify a filename." >&2; return 2; }
egrep "\i(\[.*\])?" "" |
cut -d "{" -f2 | cut -d "}" -f1
}
我正在编写我的第一个 bash 脚本,用于分析具有不同正则表达式的文本文档。以下命令完全按照预期执行:
egrep "\i(\[.*\])?" "" | cut -d "{" -f2 | cut -d "}" -f1
我决定将这个命令移动到一个函数中,因为我需要多次执行它。问题是:当它在函数内部时,我得到一个 "egrep : no such file or directory"-Error。这是代码:
function printThis() {
egrep "\i(\[.*\])?" "" | cut -d "{" -f2 | cut -d "}" -f1
}
...
printThis
我确定我犯了一个完全初学者的错误,但我似乎找不到它。我还替换了我的代码,因此它以 cat 命令开头。在那种情况下,我会收到以 "cat : ..."
开头的相同错误感谢您的宝贵时间。
你在调用 printThis()
时没有参数,但它需要一个 (</code>)</strong> - 实际上,你传递的是 <em>空字符串</em>作为<code>egrep
的文件名,这就是它所抱怨的。
更新:事实证明,OP 的错误假设是函数会看到相同的位置参数(</code>、<code>
、. ..) 作为封闭脚本范围。
相反,参数必须显式传递给函数;例如,通过以下方式传递第一个参数:printThis ""
;使用"$@"
传递所有参数。
此答案的其余部分涉及如何检查函数内的强制参数。
如果您希望
printThis()
使用stdin输入,只需删除""
:grep
将接受输入默认来自 stdin(但如果至少给出 1 个文件名操作数,将忽略 stdin 输入)。如果你确实想传递一个文件名操作数:强制一个被传递的简单方法是将 shell 参数扩展与
${1:?<errMsg>}
构造一起使用,它会退出整个 shell - 而不仅仅是函数! - 使用给定的错误消息和1
的退出代码,如果</code> 缺失或为空;例如:</p></li> </ul> <pre><code>function printThis() { : "${1:?$FUNCNAME: ERROR: Please specify a filename.}" egrep "\i(\[.*\])?" "" | cut -d "{" -f2 | cut -d "}" -f1 } # ... # Calling `printThis` without a filename now aborts the script and # reports "... printThis: ERROR: Please specify a filename." printThis
注意:虽然上述强制存在带有有意义的错误消息的参数值的方法很方便,但由于以下几个原因它很棘手:
- 它终止了整个 shell,而不仅仅是函数,因此来自同一个 shell 的调用者没有机会处理错误。
- 必须注意不要将构造放在 subshell 中,因为只有 subshell 才会终止,并且执行会继续;例如,
cat -n "${1:?missing file}" | ...
只会终止cat
运行 中的子 shell,而不是当前的 shell(默认情况下,所有管道段 运行他们自己的子shell)。这就是为什么上面的代码使用:
、null utility 作为自己的语句来检查参数的原因。 - 打印的错误消息总是包含一个可能会分散注意力的序言,说明脚本的完整文件名和违规行号,例如
/Users/jdoe/scripts/foo: line 7:
因此,一种更好(尽管更冗长)的方法是使用显式检查:
function printThis() { [[ -n ]] || { echo "$FUNCNAME: Please specify a filename." >&2; return 2; } egrep "\i(\[.*\])?" "" | cut -d "{" -f2 | cut -d "}" -f1 }