如何在换行符分隔列表中使用bash的选择?

时间:2017-07-06 21:13:22

标签: arrays bash shell select

如何在换行符分隔列表中使用bash的选择?

我实际上是在尝试改进工作脚本中的以下代码段:

# for example
nwd=/media/$USER/some-drive

# This makes a newline-separated list. I'm open to options that make a
# list in a different fashion. I usually loop with find -print0 for this
# kind of thing, but I don't know an easy way to omit a particular
# element ($nwd) from a null-separated list.
volumes="$( ls /media/$USER | grep -v "$( basename -- "$nwd" )" )"

# If there's only one option, I don't need the user to choose.
if [ 1 -eq "$( echo "$volumes" | wc -l )" ]; then
  mount_point="/media/$USER/$volumes"
else
  # KNOWN BUG: It is impossible to select devices with spaces in their names.
  echo "Please select the appropriate device:"
  select mount_point in $volumes Quit; do
    case "$mount_point" in
    Quit ) exit $EXIT_USER_HALT;;
    '' ) echo "Invalid option. Try another one." >&2;continue;;
    * ) break;;
    esac
  done
  mount_point="/media/$USER/$mount_point"
fi

2 个答案:

答案 0 :(得分:3)

使用扩展模式,您可以使用所需的文件名填充数组:

shopt -s extglob
nwd=/media/$USER/some-drive
volumes=( /media/$USER/!("$(basename -- "$nwd")") )
# Or more generally,
# volumes=( "$(dirname -- "$nwd")"/!("$(basename -- "$nwd")") )

然后你可以将数组用作

if (( ${#volumes[@]} == 1 )); then
    mount_point="/media/$USER/$volumes"  # or ${volumes[0]}
else
    echo "Please select the appropriate device:"
    select mount_point in "${volumes[@]}" Quit; do
        case $mount_point in
            Quit) exit $EXIT_USER_HALT ;;
            '') echo "Invalid option. Try another one." >&2; continue ;;
            *) break ;;
        esac
    done
fi

使用数组还可以修复无法选择名称包含空格的装入点的问题。 (实际上,它将与任何有效文件路径一起使用,包括那些可能包含glob元字符或换行符的文件路径。)

答案 1 :(得分:2)

通过设置IFS=$'\n',您的list将在换行符上拆分,例如:

#!/bin/bash
list=$'one\ntwo\nthree'

IFS=$'\n'
select item in $list; do
    case "$item" in
        one) echo "1";;
        two) echo "2";;
        *) break;;
    esac
done

请确保在local IFS的功能中执行此操作,或稍后手动恢复IFS

如果您希望文件名(在列表中)包含路径名扩展模式字符*?[,则应将上面的select语句块包装起来使用set -fset +f可以防止这些模式扩展为路径名。它还会阻止扩展的全局扩展(如果你启用了extglob)。