验证Bash脚本的参数

nic*_*ckf 91 validation bash shell

我想出了一个基本的,以帮助自动删除多个文件夹,因为它们变得不必要.

#!/bin/bash
rm -rf ~/myfolder1/$1/anotherfolder
rm -rf ~/myfolder2/$1/yetanotherfolder
rm -rf ~/myfolder3/$1/thisisafolder
Run Code Online (Sandbox Code Playgroud)

这是这样的:

./myscript.sh <{id-number}>
Run Code Online (Sandbox Code Playgroud)

问题是,如果你忘记输入id-number (就像我之前那样),那么它可能会删除你真正不想删除的很多东西.

有没有办法可以在命令行参数中添加任何形式的验证?在我的情况下,最好检查a)是否有一个参数,b)它的数字,以及c)该文件夹是否存在; 在继续脚本之前.

Bri*_*ell 152

#!/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
Run Code Online (Sandbox Code Playgroud)

编辑:我错过了关于检查目录是否存在的部分,所以我添加了,完成脚本.此外,还讨论了评论中提出的问题; 修复了正则表达式,切换==eq.

据我所知,这应该是一个便携式,POSIX兼容的脚本; 它不使用任何bashisms,这实际上很重要,因为/bin/sh在Ubuntu实际上是dash这些天,而不是bash.


lhu*_*ath 21

sh通过解决方案Brian Campbell,而高贵和很好的执行,有一些问题,所以我想我会提供我自己的bash解决方案.

sh一个问题:

  • 波形符号~/foo不会扩展到heredocs内的homedirectory.无论何时通过read声明阅读或在rm声明中引用.这意味着你会得到No such file or directory错误.
  • 分离grep和基本操作等是愚蠢的.特别是当你使用蹩脚的外壳来避免重击"沉重"时.
  • 我还注意到一些引用问题,例如他的参数扩展echo.
  • 虽然很少见,但该解决方案无法处理包含换行符的文件名.(几乎没有任何解决方案sh可以应对它们 - 这就是为什么我几乎总是喜欢bash它,它更具防弹性,并且在使用时更难以利用).

虽然,是的,使用/bin/sh你的hashbang意味着你必须bash不惜一切代价避免主义,你可以使用bash你喜欢的所有主义,甚至在Ubunutu或什么时候,当你诚实并放在#!/bin/bash顶部.

所以,这是一个bash更小,更清洁,更透明,可能"更快",更具防弹性的解决方案.

[[ -d $1 && $1 != *[^0-9]* ]] || { echo "Invalid input." >&2; exit 1; }
rm -rf ~/foo/"$1"/bar ...
Run Code Online (Sandbox Code Playgroud)
  1. 各地注意引号$1rm声明!
  2. -d检查也将失败,如果$1是空的,所以这两项检查于一体.
  3. 我出于某种原因避免了正则表达式.如果必须=~在bash中使用,则应将正则表达式放在变量中.在任何情况下,像我这样的球体总是更受欢迎,并且支持更多的bash版本.


Joh*_*itb 14

我会用bash的[[:

if [[ ! ("$#" == 1 && $1 =~ ^[0-9]+$ && -d $1) ]]; then 
    echo 'Please pass a number that corresponds to a directory'
    exit 1
fi
Run Code Online (Sandbox Code Playgroud)

我发现这个常见问题是一个很好的信息来源.


Boi*_*ill 12

不像上面的答案一样防弹,但仍然有效:

#!/bin/bash
if [ "$1" = "" ]
then
  echo "Usage: $0 <id number to be cleaned up>"
  exit
fi

# rm commands go here
Run Code Online (Sandbox Code Playgroud)

  • 它应该是“exit 1”以确保命令返回失败代码。 (3认同)

shm*_*ael 10

使用set -u会导致任何未设置的参数引用立即使脚本失败.

http://www.davidpashley.com/articles/writing-robust-shell-scripts.html


And*_*ewD 10

一行 Bash 参数验证,带或不带目录验证

以下是一些对我有用的方法。您可以在全局脚本命名空间中使用它们(如果在全局命名空间中,则无法引用函数内置变量)

又快又脏的一个衬里

: ${1?' You forgot to supply a directory name'}
Run Code Online (Sandbox Code Playgroud)

输出:

./my_script: line 279: 1: You forgot to supply a directory name
Run Code Online (Sandbox Code Playgroud)

Fancier - 提供函数名称和用法

${1? ERROR Function: ${FUNCNAME[0]}() Usage: " ${FUNCNAME[0]} directory_name"}
Run Code Online (Sandbox Code Playgroud)

输出:

./my_script: line 288: 1:  ERROR Function: deleteFolders() Usage:  deleteFolders directory_name
Run Code Online (Sandbox Code Playgroud)

添加复杂的验证逻辑,而不会使当前的功能变得混乱

在接收参数的函数或脚本中添加以下行。

: ${1?'forgot to supply a directory name'} && validate $1 || die 'Please supply a valid directory'
Run Code Online (Sandbox Code Playgroud)

然后您可以创建一个验证函数来执行类似的操作

validate() {

    #validate input and  & return 1 if failed, 0 if succeed
    if [[ ! -d "$1" ]]; then
        return 1
    fi
}
Run Code Online (Sandbox Code Playgroud)

以及一个在失败时中止脚本的 die 函数

die() { echo "$*" 1>&2 ; exit 1; }
Run Code Online (Sandbox Code Playgroud)

对于其他参数,只需添加一行,复制格式即可。

: ${1?' You forgot to supply the first argument'}
: ${2?' You forgot to supply the second argument'}
Run Code Online (Sandbox Code Playgroud)


gun*_*uns 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
Run Code Online (Sandbox Code Playgroud)

  • 为什么需要双[[]]? (2认同)

wha*_*ley 8

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
Run Code Online (Sandbox Code Playgroud)


Mat*_*ttK 5

您可以通过执行以下操作来紧凑地验证点a和b:

#!/bin/sh
MYVAL=$(echo ${1} | awk '/^[0-9]+$/')
MYVAL=${MYVAL:?"Usage - testparms <number>"}
echo ${MYVAL}
Run Code Online (Sandbox Code Playgroud)

这给了我们...

$ ./testparams.sh 
Usage - testparms <number>

$ ./testparams.sh 1234
1234

$ ./testparams.sh abcd
Usage - testparms <number>
Run Code Online (Sandbox Code Playgroud)

该方法在sh中应该可以正常工作。