由于自动提交和推送的脚本存在一些问题,我想实现一个白名单。
计划是,只允许在路径中使用模式"foo"和"bar"提交。
#!/bin/sh
WHITELIST="foo bar"
WRKDIR=/home/athur/workwork/test/repo
cd $WRKDIR
git add -A
for file in `git diff --cached -p --name-status | cut -c3-`; do
if [[ "$file" == *"$WHITELIST"* ]] ; then
echo "$file is on whitelist"
else
echo "$file is not on whitelist. Commit aborted."
exit 1
fi
done
问题是,它总是使用"else"子句。 我找不到问题。谢谢
作为最佳实践方法,请考虑:
#!/usr/bin/env bash
# ^^^^ important: [[ ]] is not guaranteed to work with bin/sh
whitelist_re='(foo|bar)'
workdir=/home/athur/workwork/test/repo
cd -- "$workdir" || exit
git add -A
while IFS= read -r filename; do
if [[ $file =~ $whitelist ]]; then
echo "$file is on whitelist" >&2
else
echo "$file is not on whitelist; commit aborted." >&2
exit 1
fi
done < <(git diff --cached --name-only)
要演练更改,请执行以下操作:
- Shebang 将
bash
指定为 shell,这保证了像[[ ]]
和<(...)
这样的扩展将可用——这是/bin/sh
无法保证的。 - 使用
while read
循环而不是尝试使用for
遍历面向行的数据;请参阅DontReadLinesWithFor来解释此更改背后的原因。 - 白名单被指定为符合 ERE 的正则表达式,以便
=~
可用于测试值是否匹配。 - 我们首先使用
--name-only
仅生成名称,而不是使用git diff --cached --name-status
然后使用cut
在事后删除状态数据。 - 使用小写变量名称符合 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html 中给出的约定,指定 POSIX 定义的工具将全大写的 shell 和环境变量名称用于其自身目的,并且至少保留一个小写字符的名称供应用程序使用。(请记住,设置 shell 变量会覆盖任何同名的环境变量,因此即使不使用
export
,这些约定也适用(。
顺便说一句,如果您只是想找出是否存在任何不匹配的文件,而不知道这些文件是哪些文件,您可以使用:
#!/bin/sh
# ^^ actually safe here, as no non-POSIX functionality is used
whitelist_re='foo|bar'
if git diff --cached --name-only | grep -qEv "$whitelist_re"; then
echo "At least one file is not on whitelist; commit aborted" >&2
exit 1
fi
使用显式列表
在这种情况下,==
不是对称的,**
似乎用得不好。
试试"$WHITELIST" == *"$file"*
.
(灵感来自如何检查 BASH 中的列表中是否存在变量(
请注意,使用您的WHITELIST
,只有foo
和bar
的文件才会被列入白名单。
检测模式
如果需要检测单个模式,则可能需要构造如下函数:
for entry in $WHITELIST ; do
if [[ "$file" =~ $entry ]] ; then
return 0
fi
done
return 1