我想出了一个基本的文件,以帮助自动删除多个文件夹,因为它们不再需要。
#!/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)该文件夹存在;在继续编写脚本之前。
答案 0 :(得分:148)
#!/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
。
答案 1 :(得分:20)
sh
Brian Campbell
解决方案虽然高尚且执行得很好,但有一些问题,所以我想我会提供自己的bash
解决方案。
sh
的问题:
~/foo
中的代字号未扩展到heredocs内的homedirectory。当它被read
语句读取或在rm
语句中引用时都不会。这意味着您将收到No such file or directory
错误。grep
这样的基本操作是愚蠢的。特别是当你使用蹩脚的外壳来避免重击“重”时。echo
中的参数扩展问题。sh
中几乎没有任何解决方案可以应对它们 - 这就是为什么我几乎总是喜欢bash
,它更具防弹性,并且在使用时更难以利用。)虽然,是的,使用/bin/sh
代表你的主题意味着你必须不惜一切代价避免bash
主义,你可以使用你喜欢的所有bash
主义,甚至在Ubunutu或什么时候使用你是诚实的,并把#!/bin/bash
放在最顶层。
所以,这是一个bash
解决方案,它更小,更清洁,更透明,可能“更快”,更具防弹性。
[[ -d $1 && $1 != *[^0-9]* ]] || { echo "Invalid input." >&2; exit 1; }
rm -rf ~/foo/"$1"/bar ...
$1
声明中rm
周围的引号!-d
为空,则$1
检查也会失败,因此在一个检查中进行了两次检查。=~
,则应将正则表达式放在变量中。在任何情况下,像我这样的球体总是更受欢迎,并且支持更多的bash版本。答案 2 :(得分:14)
我会使用bash的[[
:
if [[ ! ("$#" == 1 && $1 =~ ^[0-9]+$ && -d $1) ]]; then
echo 'Please pass a number that corresponds to a directory'
exit 1
fi
我发现this faq是一个很好的信息来源。
答案 3 :(得分:12)
不像上述答案那样具有防弹性,但仍然有效:
#!/bin/bash
if [ "$1" = "" ]
then
echo "Usage: $0 <id number to be cleaned up>"
exit
fi
# rm commands go here
答案 4 :(得分:10)
使用set -u
会导致任何未设置的参数引用立即使脚本失败。
http://www.davidpashley.com/articles/writing-robust-shell-scripts.html
答案 5 :(得分:8)
使用'-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
答案 6 :(得分:7)
test(man test
)的手册页提供了可以在bash中用作布尔运算符的所有可用运算符。在脚本(或函数)的开头使用这些标志进行输入验证,就像在任何其他编程语言中一样。例如:
if [ -z $1 ] ; then
echo "First parameter needed!" && exit 1;
fi
if [ -z $2 ] ; then
echo "Second parameter needed!" && exit 2;
fi
答案 7 :(得分:5)
您可以通过执行以下操作来紧凑地验证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中应该可以正常工作。
答案 8 :(得分:2)
有些方法对我有用。您可以在全局脚本名称空间中使用它们(如果在全局名称空间中,则不能引用函数的内置变量)
快速而脏的一根衬里
: ${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'}
答案 9 :(得分:1)
老帖子,但我认为无论如何我都可以做出贡献。
可以说一个脚本不是必需的,并且可以从命令行执行对外卡的一些容忍。
在任何地方匹配。让我们删除任何子文件夹
$ 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}