Проверка параметров на 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) эта папка существует; прежде чем продолжить с script.

Ответ 1

#!/bin/sh
die () {
    echo >&2 "[email protected]"
    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

edit. Я пропустил часть проверки, если сначала существуют каталоги, поэтому я добавил это, заполнив script. Кроме того, рассмотрели вопросы, поднятые в комментариях; исправлено регулярное выражение, переключено с == на eq.

Это должен быть портативный POSIX-совместимый script, насколько я могу судить; он не использует никаких базизмов, что на самом деле важно, потому что /bin/sh на Ubuntu на самом деле dash в эти дни, а не bash.

Ответ 2

Решение sh от Brian Campbell, хотя оно благородно и хорошо выполнено, имеет несколько проблем, поэтому я решил предоставить свое собственное решение bash.

Проблемы с sh one:

  • Тильда в ~/foo не распространяется на ваш родной каталог внутри heredocs. И ни когда он не читается оператором read или не указан в инструкции rm. Это означает, что вы получите ошибки No such file or directory.
  • Выключение grep, а для основных операций - глупое. Особенно, когда вы используете дерьмовую оболочку, чтобы избежать "тяжелого" веса bash.
  • Я также заметил несколько цитат, например, вокруг расширения параметра в его echo.
  • Редко, решение не может справиться с именами файлов, которые содержат символы новой строки. (Практически никакое решение в sh не может справиться с ними - вот почему я почти всегда предпочитаю bash, он гораздо более пуленепробиваемый и более трудный для использования при его использовании).

Хотя, используя /bin/sh для вашего хеш-бэнга, вы должны избегать bash isms любой ценой, вы можете использовать все теги 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, вы должны поместить регулярное выражение в переменную. В любом случае, globs, подобные моим, всегда предпочтительнее и поддерживается в гораздо более bash версиях.

Ответ 3

Я бы использовал bash [[:

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

Я нашел этот faq, чтобы быть хорошим источником информации.

Ответ 4

Не как пуленепробиваемый, как вышеприведенный ответ, но все же эффективный:

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

# rm commands go here

Ответ 5

Используйте '-z' для проверки пустых строк и '-d для проверки каталогов.

if [[ -z "[email protected]" ]]; then
    echo >&2 "You must supply an argument!"
    exit 1
elif [[ ! -d "[email protected]" ]]; then
    echo >&2 "[email protected] is not a valid directory!"
    exit 1
fi

Ответ 7

Страница man для теста (man test) предоставляет все доступные операторы, которые вы можете использовать в качестве логических операторов в bash. Используйте эти флаги в начале ваших script (или функций) для проверки ввода так же, как и на любом другом языке программирования. Например:

if [ -z $1 ] ; then
  echo "First parameter needed!" && exit 1;
fi

if [ -z $2 ] ; then
  echo "Second parameter needed!" && exit 2;
fi

Ответ 8

Вы можете точно проверить точки 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.

Ответ 9

Старый пост, но я решил, что могу в любом случае внести свой вклад.

A script, возможно, не требуется, и с некоторой допустимостью к диким картам можно было бы выполнить из командной строки.

  • дикий везде соответствующий. Позволяет удалить любое появление подпапки

    $ rm -rf ~/*/folder/*
    
  • Итерация оболочки. Позволяет удалить конкретные пре и почтовые папки с одной строкой

    $ rm -rf ~/foo{1,2,3}/folder/{ab,cd,ef}
    
  • Оболочка с итерацией + var (BASH).

    $ var=bar rm -rf ~/foo{1,2,3}/${var}/{ab,cd,ef}