如何在换行符分隔列表中使用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
答案 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 -f
和set +f
可以防止这些模式扩展为路径名。它还会阻止扩展的全局扩展(如果你启用了extglob
)。