检查变量是否仅包含我想要的内容,而没有其他内容

MrV*_*dji 6 grep bash

我正在编写一个脚本来从源代码构建软件,并且有一个--platforms选项。我想允许用户选择多个项目,但我不知道如何防止他们犯错。

例子:

read -p "For what platforms do you wish to build [mac/win/linux32/linux64/all] ? "

if [[ -n "`echo $REPLY | grep 'win\|mac\|linux32\|linux64\|all`" ]] ; then
    echo "ok"
else 
    echo "not ok"
fi
Run Code Online (Sandbox Code Playgroud)

如果用户回答linux32,应该没问题(而且确实如此)

如果用户回答linux32,mac,应该没问题(而且确实如此)

如果用户回答lulz,则不应该(事实并非如此)

如果用户回答linux32,lulz,则不应该(这是我的问题)

我想知道您是否知道一种方法可以让用户输入他们想要的任何内容,以逗号分隔,但前提是它是脚本提供的选项之一,所以在这种情况下linux32 linux64 mac win all.

也许case有一种方法可以允许多个输入,或者添加一个elif $REPLY contains anything else than what we want. 另一个想法,可以awk用吗?我无法弄清楚自己该怎么做。

Gil*_*il' 5

read可以将输入分解为单词并将结果存储在数组中。将IFS变量设置为单词分隔符(它需要是单个字符,而不是字符串——如果 的值IFS包含多个字符,那么每个字符都是一个单词分隔符)。

IFS=, read -a platforms
Run Code Online (Sandbox Code Playgroud)

然后根据支持的平台集检查数组的每个元素。

for p in "${platforms[@]}"; do
  case "$p" in
    win|mac|linux32|linux64) :;;
    all) platforms=(win mac linux32 linux64);;
    *) printf 1>&2 "Unsupported platform: %s\n" "$p"; return 2;;
  esac
done
Run Code Online (Sandbox Code Playgroud)

您还可以一次性比较一组平台。如果您不想在检查代码中对支持的平台集进行硬编码,这会更方便。

supported_platforms=(win mac linux32 linux64)
IFS=, read -a platforms
bad_platform_names=($(comm -23 <(printf '%s\n' all "${platforms[@]}" | sort -u) \
                               <(printf '%s\n' "${supported_platforms[@]}" | sort -u)))
if [[ ${#bad_platform_names[@]} -ne 0 ]]; then
  printf "Unsupported platform: %s\n" "${bad_platform_names[@]}"
  exit 1
fi
if printf '%s\n' "${platforms[@]}" | grep -qx all; then
  platforms=("${supported_platforms[@]}")
fi
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用select内置函数一次提示一个平台。

¹当然,如果您愿意,您可以在纯 bash 中执行此操作。


arn*_*efm 5

尝试这个!

buildvar=0
read -p "For what platforms do you wish to build [mac/win/linux32/linux64/all] ? " input
IFS=',' read -a options <<< "$input"

for option in "${options[@]}"
 do
  case "$option" in
    linux32)
        buildcommand="linux32" && buildvar=1
        ;;
    linux64)
        [ $buildvar == 1 ] && buildcommand="$buildcommand",linux64 || buildcommand="linux64" && buildvar=1
        ;;  
    mac)
        [ $buildvar == 1 ] && buildcommand="$buildcommand",mac || buildcommand="mac" && buildvar=1
        ;;  
    win)
        [ $buildvar == 1 ] && buildcommand="$buildcommand",win || buildcommand="win" && buildvar=1
        ;;
    all)
        buildcommand="all" && buildvar=1
        ;;
    *) 
        echo "'$option' was ignored." 
        ;;  
        esac
    done

[ $buildvar == "0" ] && echo "Incorrect input. Default build selected." && buildcommand="default"

echo "=> $buildcommand"
Run Code Online (Sandbox Code Playgroud)

这将提示输入逗号分隔的选项列表。然后,它将将此列表拆分为一个数组,并遍历各个元素,分别检查每个元素,然后将所有“好”元素合并到一个变量中。


nyu*_*a7h 1

arnefm答案简化/改进版本:

read -p 'Enter a comma-separated list of platforms to build for [win/mac/linux32/linux64/all]: ' input
IFS=',' read -a options <<< "$input"

shopt -s extglob

for option in "${options[@]}"; do
    case "$option" in
        win|mac|linux@(32|64)|all)
            buildcommand="${buildcommand:+$buildcommand,}$option"
            buildvar=1;;
        *)
            printf 'Invalid option "%s" ignored.\n' "$option" >&2;;
    esac
done

IFS=',' read -a options <<< "$buildcommand"

for option in "${options[@]}"; do
    if [[ $option == 'all' ]]; then
        buildcommand='all'
        break
    fi
done

if (( !buildvar )); then
    echo 'Incorrect input. Default build selected.' >&2
    buildcommand='default'
fi
Run Code Online (Sandbox Code Playgroud)