提问人:nickf 提问时间:3/31/2009 最后编辑:codeforesternickf 更新时间:8/14/2020 访问量:209689
验证 Bash 脚本的参数
Validating parameters to a Bash script
问:
我想出了一个基本的方法来帮助自动删除一些不需要的文件夹的过程。
#!/bin/bash
rm -rf ~/myfolder1/$1/anotherfolder
rm -rf ~/myfolder2/$1/yetanotherfolder
rm -rf ~/myfolder3/$1/thisisafolder
这是这样唤起的:
./myscript.sh <{id-number}>
问题是,如果你忘记输入(就像我刚才所做的那样),那么它可能会删除很多你真的不想删除的东西。id-number
有没有办法可以向命令行参数添加任何形式的验证?就我而言,最好检查 a) 有一个参数,b) 它是数字,以及 c) 该文件夹存在;在继续脚本之前。
答:
使用 '-z' 测试空字符串,使用 '-d 检查目录。
if [[ -z "$@" ]]; then
echo >&2 "You must supply an argument!"
exit 1
elif [[ ! -d "$@" ]]; then
echo >&2 "$@ is not a valid directory!"
exit 1
fi
评论
#!/bin/sh
die () {
echo >&2 "$@"
exit 1
}
[ "$#" -eq 1 ] || die "1 argument required, $# provided"
echo $1 | grep -E -q '^[0-9]+$' || die "Numeric argument required, $1 provided"
while read dir
do
[ -d "$dir" ] || die "Directory $dir does not exist"
rm -rf "$dir"
done <<EOF
~/myfolder1/$1/anotherfolder
~/myfolder2/$1/yetanotherfolder
~/myfolder3/$1/thisisafolder
EOF
编辑:我错过了关于首先检查目录是否存在的部分,所以我添加了它,完成了脚本。此外,还解决了评论中提出的问题;修复了正则表达式,从 切换到 .==
eq
据我所知,这应该是一个可移植的、符合 POSIX 标准的脚本;它不使用任何 bashisms,这实际上很重要,因为在 Ubuntu 上实际上是现在,而不是./bin/sh
dash
bash
评论
不像上面的答案那样防弹,但仍然有效:
#!/bin/bash
if [ "$1" = "" ]
then
echo "Usage: $0 <id number to be cleaned up>"
exit
fi
# rm commands go here
评论
exit 1
test () 的手册页提供了可在 bash 中用作布尔运算符的所有可用运算符。在脚本(或函数)的开头使用这些标志进行输入验证,就像在任何其他编程语言中一样。例如:man test
if [ -z $1 ] ; then
echo "First parameter needed!" && exit 1;
fi
if [ -z $2 ] ; then
echo "Second parameter needed!" && exit 2;
fi
我会使用 bash 的:[[
if [[ ! ("$#" == 1 && $1 =~ ^[0-9]+$ && -d $1) ]]; then
echo 'Please pass a number that corresponds to a directory'
exit 1
fi
我发现这个常见问题解答是一个很好的信息来源。
解决方案虽然高尚且执行良好,但也存在一些问题,所以我想我会提供自己的解决方案。sh
Brian Campbell
bash
一个问题:sh
- 中的波浪号不会扩展到您在 heredocs 中的主目录。当它被语句阅读或在语句中引用时,两者都不是。这意味着您会遇到错误。
~/foo
read
rm
No such file or directory
- 对于基本操作来说,分叉等是愚蠢的。尤其是当你使用一个蹩脚的外壳来避免 bash 的“沉重”重量时。
grep
- 我还注意到一些引用问题,例如他的 .
echo
- 虽然很少见,但该解决方案无法处理包含换行符的文件名。(几乎没有任何解决方案可以应对它们 - 这就是为什么我几乎总是更喜欢,如果使用得当,它更防弹,更难利用)。
sh
bash
虽然,是的,用于你的哈希爆炸意味着你必须不惜一切代价避免主义,但你可以使用你喜欢的所有主义,即使在 Ubuntu 或其他什么地方,当你诚实并放在顶部时。/bin/sh
bash
bash
#!/bin/bash
所以,这里有一个更小、更干净、更透明、可能“更快”、更防弹的解决方案。bash
[[ -d $1 && $1 != *[^0-9]* ]] || { echo "Invalid input." >&2; exit 1; }
rm -rf ~/foo/"$1"/bar ...
- 请注意声明中的引号!
$1
rm
- 如果为空,检查也会失败,因此这是两个检查合二为一。
-d
$1
- 我避免使用正则表达式是有原因的。如果你必须在 bash 中使用,你应该把正则表达式放在一个变量中。无论如何,像我这样的 glob 总是更可取的,并且在更多的 bash 版本中得到了支持。
=~
评论
$1 != *[^0-9]*
您可以通过执行如下操作来紧凑地验证点 a 和 b:
#!/bin/sh
MYVAL=$(echo ${1} | awk '/^[0-9]+$/')
MYVAL=${MYVAL:?"Usage - testparms <number>"}
echo ${MYVAL}
这给了我们......
$ ./testparams.sh
Usage - testparms <number>
$ ./testparams.sh 1234
1234
$ ./testparams.sh abcd
Usage - testparms <number>
此方法在 sh 中应该可以正常工作。
使用 它将导致任何未设置的参数引用立即使脚本失败。set -u
请参阅文章:编写健壮的 Bash Shell 脚本 - David Pashley.com。
评论
旧帖子,但我想我无论如何都可以做出贡献。
可以说,脚本不是必需的,并且可以从命令行执行对通配符具有一定的容忍度。
狂野无处不在的匹配。让我们删除任何出现的子“文件夹”
$ rm -rf ~/*/folder/*
Shell 迭代。让我们用一行删除特定的 pre 和 post 文件夹
$ rm -rf ~/foo{1,2,3}/folder/{ab,cd,ef}
Shell 迭代 + var(BASH 测试)。
$ var=bar rm -rf ~/foo{1,2,3}/${var}/{ab,cd,ef}
一行 Bash 参数验证,带和不带目录验证
以下是一些对我有用的方法。可以在全局脚本命名空间中使用它们(如果在全局命名空间中,则不能引用函数内置变量)
快速而肮脏的一个衬垫
: ${1?' You forgot to supply a directory name'}
输出:
./my_script: line 279: 1: You forgot to supply a directory name
Fancier - 供应函数名称和用法
${1? ERROR Function: ${FUNCNAME[0]}() Usage: " ${FUNCNAME[0]} directory_name"}
输出:
./my_script: line 288: 1: ERROR Function: deleteFolders() Usage: deleteFolders directory_name
添加复杂的验证逻辑,而不会使当前函数混乱
在接收参数的函数或脚本中添加以下行。
: ${1?'forgot to supply a directory name'} && validate $1 || die 'Please supply a valid directory'
然后,您可以创建一个验证函数,该函数执行类似操作
validate() {
#validate input and & return 1 if failed, 0 if succeed
if [[ ! -d "$1" ]]; then
return 1
fi
}
以及一个在失败时中止脚本的 die 函数
die() { echo "$*" 1>&2 ; exit 1; }
对于其他参数,只需添加一行,复制格式即可。
: ${1?' You forgot to supply the first argument'}
: ${2?' You forgot to supply the second argument'}
上一个:XSLT 值得吗?[已结束]
下一个:如何在TBODY元素之间放置间距
评论