验证 Bash 脚本的参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/699576/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Validating parameters to a Bash script
提问by nickf
I came up with a basic one to help automate the process of removing a number of folders as they become unneeded.
我想出了一个基本的方法来帮助自动化删除一些不需要的文件夹的过程。
#!/bin/bash
rm -rf ~/myfolder1//anotherfolder
rm -rf ~/myfolder2//yetanotherfolder
rm -rf ~/myfolder3//thisisafolder
This is evoked like so:
这是这样唤起的:
./myscript.sh <{id-number}>
The problem is that if you forget to type in the id-number
(as I did just then), then it could potentially delete a lot of things that you really don't want deleted.
问题是,如果你忘记输入id-number
(就像我刚才那样),那么它可能会删除很多你真的不想删除的东西。
Is there a way you can add any form of validation to the command line parameters?In my case, it'd be good to check that a) there is one parameter, b) it's numerical, and c) that folder exists; before continuing with the script.
有没有办法可以向命令行参数添加任何形式的验证?就我而言,最好检查一下 a) 有一个参数,b) 它是数字,以及 c) 该文件夹是否存在;在继续脚本之前。
回答by Brian Campbell
#!/bin/sh
die () {
echo >&2 "$@"
exit 1
}
[ "$#" -eq 1 ] || die "1 argument required, $# provided"
echo | grep -E -q '^[0-9]+$' || die "Numeric argument required, provided"
while read dir
do
[ -d "$dir" ] || die "Directory $dir does not exist"
rm -rf "$dir"
done <<EOF
~/myfolder1//anotherfolder
~/myfolder2//yetanotherfolder
~/myfolder3//thisisafolder
EOF
edit: I missed the part about checking if the directories exist at first, so I added that in, completing the script. Also, have addressed issues raised in comments; fixed the regular expression, switched from ==
to eq
.
编辑:我错过了首先检查目录是否存在的部分,所以我添加了它,完成了脚本。此外,已经解决了评论中提出的问题;修复了正则表达式,从 切换==
到eq
。
This should be a portable, POSIX compliant script as far as I can tell; it doesn't use any bashisms, which is actually important because /bin/sh
on Ubuntu is actually dash
these days, not bash
.
据我所知,这应该是一个可移植的、符合 POSIX 标准的脚本;它不使用任何 bashisms,这实际上很重要,因为/bin/sh
在 Ubuntu 上实际上是dash
这些天,而不是bash
.
回答by lhunath
The sh
solution by Brian Campbell
, while noble and well executed, has a few problems, so I thought I'd provide my own bash
solution.
由 的sh
解决方案Brian Campbell
虽然高尚且执行良好,但存在一些问题,因此我想我会提供自己的bash
解决方案。
The problems with the sh
one:
问题sh
之一:
- The tilde in
~/foo
doesn't expand to your homedirectory inside heredocs. And neither when it's read by theread
statement or quoted in therm
statement. Which means you'll getNo such file or directory
errors. - Forking off
grep
and such for basic operations is daft. Especially when you're using a crappy shell to avoid the "heavy" weight of bash. - I also noticed a few quoting issues, for instance around a parameter expansion in his
echo
. - While rare, the solution cannot cope with filenames that contain newlines. (Almost no solution in
sh
can cope with them - which is why I almost always preferbash
, it's far more bulletproof & harder to exploit when used well).
- 波浪号
~/foo
不会扩展到您在heredocs 中的主目录。并且无论是在read
语句中读取还是在rm
语句中引用时。这意味着你会得到No such file or directory
错误。 - 分叉
grep
等基本操作是愚蠢的。特别是当您使用蹩脚的外壳来避免 bash 的“重”重量时。 - 我还注意到一些引用问题,例如围绕他的
echo
. - 虽然很少见,但该解决方案无法处理包含换行符的文件名。(几乎没有任何解决方案
sh
可以应对它们 - 这就是为什么我几乎总是更喜欢bash
,它更防弹并且使用得当时更难利用)。
While, yes, using /bin/sh
for your hashbang means you must avoid bash
isms at all costs, you can use all the bash
isms you like, even on Ubuntu or whatnot when you're honest and put #!/bin/bash
at the top.
虽然,是的,/bin/sh
用于你的 hashbang 意味着你必须bash
不惜一切代价避免 isms ,你可以使用所有bash
你喜欢的 isms ,即使在 Ubuntu 或诸如此类的东西上,当你诚实并放在首位时#!/bin/bash
。
So, here's a bash
solution that's smaller, cleaner, more transparent, probably "faster", and more bulletproof.
所以,这里有一个bash
更小、更干净、更透明、可能“更快”、更防弹的解决方案。
[[ -d && != *[^0-9]* ]] || { echo "Invalid input." >&2; exit 1; }
rm -rf ~/foo/""/bar ...
- Notice the quotes around
$1
in therm
statement! - The
-d
check will also fail if$1
is empty, so that's two checks in one. - I avoided regular expressions for a reason. If you must use
=~
in bash, you should be putting the regular expression in a variable. In any case, globs like mine are always preferable and supported in far more bash versions.
- 各地注意引号
$1
的rm
声明! - 该
-d
检查也将失败,如果$1
是空的,所以,在一个人的两个检查。 - 我避免使用正则表达式是有原因的。如果必须
=~
在 bash 中使用,则应将正则表达式放入变量中。在任何情况下,像我这样的 glob 总是更可取,并且在更多的 bash 版本中得到支持。
回答by Johannes Schaub - litb
回答by Boiler Bill
Not as bulletproof as the above answer, however still effective:
不像上面的答案那样防弹,但仍然有效:
#!/bin/bash
if [ "" = "" ]
then
echo "Usage: if [ -z ] ; then
echo "First parameter needed!" && exit 1;
fi
if [ -z ] ; then
echo "Second parameter needed!" && exit 2;
fi
<id number to be cleaned up>"
exit
fi
# rm commands go here
回答by shmichael
Use set -u
which will cause any unset argument reference to immediately fail the script.
使用set -u
这将导致任何未设置的参数引用立即使脚本失败。
http://www.davidpashley.com/articles/writing-robust-shell-scripts.html
http://www.davidpashley.com/articles/writing-robust-shell-scripts.html
回答by whaley
The man page for test (man test
) provides all available operators you can use as boolean operators in bash. Use those flags in the beginning of your script (or functions) for input validation just like you would in any other programming language. For example:
test ( man test
)的手册页提供了您可以在 bash 中用作布尔运算符的所有可用运算符。在脚本(或函数)的开头使用这些标志进行输入验证,就像在任何其他编程语言中一样。例如:
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
回答by guns
Use '-z' to test for empty strings and '-d to check for directories.
使用 '-z' 来测试空字符串,使用 '-d 来检查目录。
#!/bin/sh
MYVAL=$(echo | awk '/^[0-9]+$/')
MYVAL=${MYVAL:?"Usage - testparms <number>"}
echo ${MYVAL}
回答by MattK
You can validate point a and b compactly by doing something like the following:
您可以通过执行以下操作来紧凑地验证点 a 和 b:
$ ./testparams.sh
Usage - testparms <number>
$ ./testparams.sh 1234
1234
$ ./testparams.sh abcd
Usage - testparms <number>
Which gives us ...
这让我们...
: ${1?' You forgot to supply a directory name'}
This method should work fine in sh.
这种方法在 sh 中应该可以正常工作。
回答by AndrewD
one liner Bash argument validation, with and without directory validation
单行 Bash 参数验证,带和不带目录验证
Here are some methods that have worked for me. You can use them in either the global script namespace (if in the global namespace, you can't reference the function builtin variables)
以下是一些对我有用的方法。您可以在全局脚本命名空间中使用它们(如果在全局命名空间中,则不能引用函数内置变量)
quick and dirty one liner
快速而肮脏的一个班轮
./my_script: line 279: 1: You forgot to supply a directory name
output:
输出:
${1? ERROR Function: ${FUNCNAME[0]}() Usage: " ${FUNCNAME[0]} directory_name"}
Fancier - supply function name and usage
Fancier - 提供函数名称和用法
./my_script: line 288: 1: ERROR Function: deleteFolders() Usage: deleteFolders directory_name
output:
输出:
: ${1?'forgot to supply a directory name'} && validate || die 'Please supply a valid directory'
Add complex validation logic without cluttering your current function
添加复杂的验证逻辑而不会使您的当前功能混乱
Add the following line within the function or script that receives the argument.
在接收参数的函数或脚本中添加以下行。
validate() {
#validate input and & return 1 if failed, 0 if succeed
if [[ ! -d "" ]]; then
return 1
fi
}
You can then create a validation function that does something like
然后,您可以创建一个验证函数,它执行类似的操作
die() { echo "$*" 1>&2 ; exit 1; }
and a die function that aborts the script on failure
以及在失败时中止脚本的 die 函数
: ${1?' You forgot to supply the first argument'}
: ${2?' You forgot to supply the second argument'}
For additional arguments, just add an additional line, replicating the format.
对于其他参数,只需添加额外的行,复制格式。
$ rm -rf ~/*/folder/*
回答by Xarses
Old post but I figured i could contribute anyway.
旧帖子,但我想无论如何我都可以做出贡献。
A script is arguably not necessary and with some tolerance to wild cards could be carried out from the command line.
脚本可以说不是必需的,并且可以从命令行执行对通配符的一些容忍。
wild anywhere matching. Lets remove any occurrence of sub "folder"
$ rm -rf ~/foo{1,2,3}/folder/{ab,cd,ef}
Shell iterated. Lets remove the specific pre and post folders with one line
$ var=bar rm -rf ~/foo{1,2,3}/${var}/{ab,cd,ef}
Shell iterated + var (BASH tested).
$ rm -rf ~/*/folder/*
狂野的任何地方匹配。让我们删除任何出现的子“文件夹”
$ rm -rf ~/foo{1,2,3}/folder/{ab,cd,ef}
壳迭代。让我们用一行删除特定的前后文件夹
$ var=bar rm -rf ~/foo{1,2,3}/${var}/{ab,cd,ef}
Shell 迭代 + var(BASH 测试)。
##代码##