我遇到了一个包含以下命令的bash脚本:
cd .git/hooks
[ `eval ls -l | grep -io 'Post-Commit' | wc -l` -eq 1 ] && echo 'post-commit file check... Pass' || echo 'post-commit file check... Fail'
我认为是检查.git/hooks
文件夹中名为post-commit
的文件。但是,即使我在目录中创建文件post-commit
,我也会得到如下输出:post-commit file check... Fail
。
我是不是做错了什么?我使用创建文件
cat > post-commit
然后我把它写进去,并用chmod +x post-commit
把它变成一个可执行文件
任何帮助都将不胜感激
虽然这个脚本似乎是针对Git挂钩的,但它在任何方面都不依赖Git,所以我删除了Git和githooks标签。它也与Linux无关,所以我放弃了Linux标签。
这里的eval
完全没有必要1我们可以放弃它:
[ `ls -l | grep -io 'Post-Commit' | wc -l` -eq 1 ] &&
echo 'post-commit file check... Pass' ||
echo 'post-commit file check... Fail'
(为了可读性,我把它分成了更多行(。
正如Losko在评论中指出的那样,[
名义上是一个外部命令。在实践中,它实际上内置在大多数shell中,包括bash,因此没有fork和exec。
然而,后引号部分确实需要一个fork和exec。形式`command`
的文本或多或少等同于形式$(command)
的代码。$(...)
形式通常更优越,因为它提供了合理的嵌套,所以如果可以选择使用哪种形式,通常应该更喜欢$(...)
形式。在任何情况下,它只是意味着:运行显示的命令并在此处插入其输出。所以我们要运行:
ls -l | grep -io 'Post-Commit' | wc -l
作为另一条评论中的金属音符。
ls -l
做了一件显而易见的事情:一个很长的清单。
grep -io
有两个标志:-i
,表示忽略大小写;-o
,表示仅将匹配部分显示为输出。因此,这将查找ls -l
输出,其中的行包含POST-COMMIT
、post-commit
、pOSt-COMmit
等等
wc -l
做了显而易见的事情:计数行。
最终结果是,我们计算文件名中包含此字符串的文件的数量。例如,一个名为this-GETS-RUN-post-COMMIThaste-er
的文件会被计数。
将此计数的最终结果与1
进行数值相等比较。如果数字是一,则运行子句的&&
部分;如果没有,则运行||
部件。
总的来说,这个脚本没有做任何有用的事情,因为它太草率了。它允许混合大小写文件名;Git没有。(然而,在OS允许不区分大小写匹配文件名的文件系统上,Git使用严格的小写字母会导致访问混合大小写或大写的名称。(如果我们发现两个或多个匹配的文件,它会抱怨,但名称只是有sub-匹配的文件在这里可能不是问题。
1shell命令中的eval
使shell首先进行各种扩展,然后运行该命令。在有用的地方——例如eval $cmd
——通常也很危险:您必须对$cmd
中的内容进行极其严格的控制。在没有扩展的地方,就像在这种情况下,它是无用的。尽量避免。