![BASH 函数不转义控制字符](https://linux22.com/image/1327927/BASH%20%E5%87%BD%E6%95%B0%E4%B8%8D%E8%BD%AC%E4%B9%89%E6%8E%A7%E5%88%B6%E5%AD%97%E7%AC%A6.png)
我有一个用来查找内容的函数,但不幸的是,每当我向其传递控制字符($intVal
或testing :
等)时,它就会卡住。我想知道修复方法是什么?
我可以理解在 grep 中使用$
或%
等:
而不进行转义会导致此问题,但由于我通过引用传递它,所以我不确定如何转义它......
无论如何,这是代码。
function ffind()
{
if [ $1 ] ; then
find -type f | grep -ir '$1' * | grep -v '.svn'
else
echo "'$1' is not a valid resource"
fi
}
例子):
$ ffind $intVal
'' is not a valid resource
$ ffind "testing :"
bash: [: testing: unary operator expected
'testing :' is not a valid resource
答案1
第一个例子
$ ffind $intVal
'' is not a valid resource
这不起作用,因为$foo
是变量的语法,并且您没有名为intVal
set 的变量,因此$intVal
被转换为空字符串。由于变量也没有加引号,因此根本没有任何参数传递给ffind
。
要修复此问题,请转义$
–\$intVal
(反斜杠)或'$intVal'
(单引号)。
如果你真的有一个名为的变量intVal
,但是,把它放在双倍的改为引号 –"$intVal"
– 这将扩大变量的值,但不会分割它。
请注意没有这样的事在 bash 中为“按引用传递”。只有按值传递和(棘手的)按名称传递。
第二个例子
$ ffind "testing :"
bash: [: testing: unary operator expected
'testing :' is not a valid resource
这不起作用,因为你忘了加引号$1
在线上if [ $1 ]
,因此它是受分词影响,并且三个参数被传递给[
内置函数:
- “
[
“ - “
testing
“ - “
:
“ - “
]
“
而不是预期的两个:
- “
[
“ - “
testing :
“ - “
]
“
示例 #1 也受此影响,因为[ $1 ]
它拆分为 (" [
", " ]
") 而不是 (" [
", "
", " ]
")。但是示例 #1 偶然成功,因为它显然[ ]
是有效的。(我不知道……)
$1
为了修复此问题,请在–周围加上双引号[ "$1" ]
。
笔记:虽然[
是标准的,但也有一个特定于 bash 的[[
运算符,它实际上具有与其余代码不同的解析规则 - 特别是,它不拆分扩展变量。在 bash 中,[[ $1 ]]
和[[ "$1" ]]
都是等效的,与它们的替代方案不同[
。
更多错误
您的函数还存在一些示例中未显示的其他问题。
find -type f | grep -ir '$1' * | grep -v '.svn'
在这一行中:
这个词
'$1'
用单引号括起来。这意味着狂欢不会扩展其内容——你实际上是在告诉grep搜索正则表达式$1
,而不是命令行参数。要解决这个问题,请改用双引号 -
"$1"
首先grep命令被告知要递归搜索内容当前目录中的所有文件(
-r
和*
通配符)。同时,你正在将输出传输
find -type f
到grep– 似乎想告诉grep搜索名称所有文件。这是行不通的,因为grep与大多数过滤器一样,如果给定一个或多个文件进行搜索,则不会从 stdin 读取。我不知道您要搜索什么——文件名或文件内容——所以选择一个:
要仅搜索文件名,请保留管道但删除文件规范:
find -type f | grep -i "$1" | ...
要仅搜索文件内容,请删除
find|
:grep -ir "$1" * | ...
它是可以结合两者,通过明确给出grep“stdin”文件:
find -type f | grep -i "$1" - * | ... find -type f | grep -i "$1" /dev/stdin * | ...
(
/dev/stdin
适用于所有 Linux 程序,而-
是使用的约定一些程序,包括 grep。)
在第二grep命令,搜索正则表达式有点太宽泛。(请记住,这是一个正则表达式,而不是固定字符串。)
.svn
甚至会匹配像“not-a-svn-file
”这样的内容。要排除
.svn
目录,请改用grep -v "/\.svn/"
。如果搜索文件内容(
grep -ir ...
),最好完全删除该grep -v
命令,并添加--exclude-dir=".svn"
到第一个命令中。
你可以停止阅读
以下项目只是很好的练习什脚本。
关键字
function
是不必要的:ffind() { ...
足够了,并且在所有 POSIX shell 中都可以工作(而function ffind
不会)。如果脚本、程序或函数失败,则应向其父级返回“失败”状态。按照惯例,Unix 程序认为
0
表示“成功”,其他情况则表示“失败”(尽管后者也有例外)。要明确返回状态,请
return <num>
在函数(或exit <num>
独立脚本)中使用:else echo "'$1' is not a valid resource" >&2 return 1 fi
类似地,错误消息不应与正常标准输出混合,而应写入标准错误(fd #2),使用
>&
重定向运算符(参见上例)。这样,您可以将正常输出重定向到文件(例如ffind intVal > results.txt
),同时仍将错误显示在屏幕上。
固定代码
ffind()
{
if [ "$1" ] ; then
grep -ir --exclude-dir=".svn" "$1" .
else
echo "'$1' is not a valid resource" >&2
return 1
fi
}
更好的工具
确认声称“比 grep 更好”。运行后ack "testing :"
会搜索源代码,并自动跳过.svn
和类似的目录。