Linux 检查Bash中的列表中是否存在变量
我正在尝试用bash编写一个脚本来检查用户输入的有效性。Linux 检查Bash中的列表中是否存在变量,linux,bash,Linux,Bash,我正在尝试用bash编写一个脚本来检查用户输入的有效性。 我想将输入(比如变量x)与有效值列表相匹配 我现在想到的是: for item in $list do if [ "$x" == "$item" ]; then echo "In the list" exit fi done 我的问题是,是否有更简单的方法来实现这一点, 类似于列表的内容。对于大多数编程语言,包含(x) 假设列表为
我想将输入(比如变量
x
)与有效值列表相匹配
我现在想到的是:
for item in $list
do
if [ "$x" == "$item" ]; then
echo "In the list"
exit
fi
done
我的问题是,是否有更简单的方法来实现这一点,类似于
列表的内容。对于大多数编程语言,包含(x)
假设列表为:
list="11 22 33"
我的代码将仅对这些值回显消息,因为list
被视为数组而不是字符串,
所有字符串操作都将验证1
,而我希望它失败。怎么样
echo $list | grep -w -q $x
您可以检查上述行的输出或$?
,以做出决定
grep-w
检查整个单词模式。添加-q
可防止重复列表
[[ $list =~ (^|[[:space:]])$x($|[[:space:]]) ]] && echo 'yes' || echo 'no'
# Checks if element "$1" is in array "$2"
# @NOTE:
# Be sure that array is passed in the form:
# "${ARR[@]}"
elementIn () {
# shopt -s nocasematch # Can be useful to disable case-matching
local e
for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
return 1
}
# Usage:
list=(11 22 33)
item=22
if elementIn "$item" "${list[@]}"; then
echo TRUE;
else
echo FALSE
fi
# TRUE
item=44
elementIn $item "${list[@]}" && echo TRUE || echo FALSE
# FALSE
或创建一个函数:
contains() {
[[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && exit(0) || exit(1)
}
for x in "item 1" "item2" "item 3" "3" "*"; do
echo -n "'$x' is "
validate "$x" && echo "valid" || echo "invalid"
done
_contains () { # Check if space-separated list $1 contains line $2
echo "$1" | tr ' ' '\n' | grep -F -x -q "$2"
}
mylist="aa bb cc"
# Positive check
if _contains "${mylist}" "${myitem}"; then
echo "in list"
fi
# Negative check
if ! _contains "${mylist}" "${myitem}"; then
echo "not in list"
fi
: Needle "list" Seperator_opt
NeedleListSep()
{
if [ 3 -gt $# ];
then NeedleListSep "$1" "$2" " ";
else case "$3$2$3" in (*"$3$1$3"*) return 0;; esac; return 1;
fi;
}
要使用它:
contains aList anItem
echo $? # 0: match, 1: failed
如果使用双括号,也可以在case语句外使用(*通配符):
string='My string';
if [[ $string == *My* ]]
then
echo "It's there!";
fi
Matvey是正确的,但你应该引用X,并考虑任何类型的“空间”(如新线),
那么,就是# list_include_item "10 11 12" "2"
function list_include_item {
local list="$1"
local item="$2"
if [[ $list =~ (^|[[:space:]])"$item"($|[[:space:]]) ]] ; then
# yes, list include item
result=0
else
result=1
fi
return $result
}
那末
`list_include_item "10 11 12" "12"` && echo "yes" || echo "no"
或
注意,对于变量,必须使用”
:
`list_include_item "$my_list" "$my_item"` && echo "yes" || echo "no"
考虑利用的关键。我认为这比正则表达式/模式匹配和循环都要好,尽管我还没有对其进行分析
declare -A list=( [one]=1 [two]=two [three]='any non-empty value' )
for value in one two three four
do
echo -n "$value is "
# a missing key expands to the null string,
# and we've set each interesting key to a non-empty value
[[ -z "${list[$value]}" ]] && echo -n '*not* '
echo "a member of ( ${!list[*]} )"
done
输出:
如果脚本中的列表是固定的,我最喜欢以下内容:
validate() {
grep -F -q -x "$1" <<EOF
item 1
item 2
item 3
EOF
}
注:
- 这与POSIX
兼容sh
不接受子字符串(如果需要,请删除grep的validate
选项)-x
将其参数解释为固定字符串,而不是常规字符串 表达式(如果需要,请删除grep的validate
选项)-F
contains() {
[[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && exit(0) || exit(1)
}
for x in "item 1" "item2" "item 3" "3" "*"; do
echo -n "'$x' is "
validate "$x" && echo "valid" || echo "invalid"
done
_contains () { # Check if space-separated list $1 contains line $2
echo "$1" | tr ' ' '\n' | grep -F -x -q "$2"
}
mylist="aa bb cc"
# Positive check
if _contains "${mylist}" "${myitem}"; then
echo "in list"
fi
# Negative check
if ! _contains "${mylist}" "${myitem}"; then
echo "not in list"
fi
: Needle "list" Seperator_opt
NeedleListSep()
{
if [ 3 -gt $# ];
then NeedleListSep "$1" "$2" " ";
else case "$3$2$3" in (*"$3$1$3"*) return 0;; esac; return 1;
fi;
}
例子
入围名单
函数show_help()
{
IT=$(CAT是
“测试我”如何“测试我”->是
)
回声“$IT”
出口
}
如果[“$1”==“帮助”]
然后
伸出援手
fi
如果[“$#”-等式0];然后
伸出援手
fi
搜索=$1
转移;
对于“$@”中的项目
做
如果[“$SEARCH_FOR”==“$ITEM”]
然后
回应“是”
出口
fi
完成
回应“否”
如果要在脚本中对值列表进行硬编码,那么使用case
进行测试相当简单。下面是一个简短的示例,您可以根据自己的需求进行调整:
for item in $list
do
case "$x" in
item1|item2)
echo "In the list"
;;
not_an_item)
echo "Error" >&2
exit 1
;;
esac
done
如果列表在运行时是一个数组变量,那么其他答案之一可能更合适。我发现使用格式
echo$list | xargs-n1 echo | grep$VALUE
更容易,如下所示:
LIST="ITEM1 ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | xargs -n1 echo | grep -e \"^$VALUE`$\" ]; then
...
fi
这适用于以空格分隔的列表,但您可以通过执行以下操作将其调整为任何其他分隔符(如:
):
LIST="ITEM1:ITEM2"
VALUE="ITEM1"
if [ -n "`echo $LIST | sed 's|:|\\n|g' | grep -e \"^$VALUE`$\"`" ]; then
...
fi
请注意,
“
是测试工作所必需的。最简单的解决方案是在原始字符串前面加上一个空格,然后使用[[]]
haystack='foo bar'
needle='bar'
if [[ " $haystack " =~ .*\ $needle\ .* ]]; then
...
fi
对于包含针作为子串的值,例如使用haystackfoo barbaz
,这不会是假阳性
(从JQuery的
hasClass()
-Method中不知羞耻地窃取了这个概念)假设目标变量只能是“二项式”或“回归”,那么下面的方法就可以了:
# Check for modeling types known to this script
if [ $( echo "${TARGET}" | egrep -c "^(binomial|regression)$" ) -eq 0 ]; then
echo "This scoring program can only handle 'binomial' and 'regression' methods now." >&2
usage
fi
您可以通过使用|(管道)字符分隔来向列表中添加更多字符串
使用egrep的优点是,您可以轻松地添加不区分大小写(-i),或者使用正则表达式检查更复杂的场景。认为我应该将解决方案添加到列表中
# Checks if element "$1" is in array "$2"
# @NOTE:
# Be sure that array is passed in the form:
# "${ARR[@]}"
elementIn () {
# shopt -s nocasematch # Can be useful to disable case-matching
local e
for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
return 1
}
# Usage:
list=(11 22 33)
item=22
if elementIn "$item" "${list[@]}"; then
echo TRUE;
else
echo FALSE
fi
# TRUE
item=44
elementIn $item "${list[@]}" && echo TRUE || echo FALSE
# FALSE
这几乎是您最初的建议,但几乎是一行代码。没有其他有效答案那么复杂,也不太依赖于bash版本(可以与旧bash一起使用)
我想我的建议在长度和风格上都可以改进。如果不是太长的话,你可以用逻辑或比较的方式将它们串在相等之间
if [ $ITEM == "item1" -o $ITEM == "item2" -o $ITEM == "item3" ]; then
echo In the list
fi
我遇到了这个确切的问题,虽然上面的问题很难看,但它比其他通用的解决方案更明显。shell内置的compgen可以在这里提供帮助。它可以获取一个带有-W标志的列表,并返回它找到的任何潜在匹配项
# My list can contain spaces so I want to set the internal
# file separator to newline to preserve the original strings.
IFS=$'\n'
# Create a list of acceptable strings.
accept=( 'foo' 'bar' 'foo bar' )
# The string we will check
word='foo'
# compgen will return a list of possible matches of the
# variable 'word' with the best match being first.
compgen -W "${accept[*]}" "$word"
# Returns:
# foo
# foo bar
我们可以编写一个函数来测试一个字符串是否等于可接受字符串的最佳匹配。这允许您分别为通过或失败返回0或1
function validate {
local IFS=$'\n'
local accept=( 'foo' 'bar' 'foo bar' )
if [ "$1" == "$(compgen -W "${accept[*]}" "$1" | head -1)" ] ; then
return 0
else
return 1
fi
}
现在,您可以编写非常干净的测试来验证字符串是否可接受
validate "blah" || echo unacceptable
if validate "foo" ; then
echo acceptable
else
echo unacceptable
fi
受公认响应启发的替代解决方案,但使用反向逻辑:
MODE="${1}"
echo "<${MODE}>"
[[ "${MODE}" =~ ^(preview|live|both)$ ]] && echo "OK" || echo "Uh?"
MODE=“${1}”
回声“”
[[“${MODE}”=~^(预览|直播|两者)$]&&echo“OK”| | echo“Uh?”
这里,输入($MODE)必须是正则表达式中的一个选项('preview'、'live'或'both'),与将整个选项列表与用户输入相匹配相反。当然,您不希望正则表达式发生更改。前面的答案没有使用我认为有用的内容。假设列表中的项目以空格分隔,请检查是否完全匹配:
echo $mylist | tr ' ' '\n' | grep -F -x -q "$myitem"
如果项目在列表中,则返回退出代码0;如果项目不在列表中,则返回退出代码1
最好将其用作函数:
contains() {
[[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && exit(0) || exit(1)
}
for x in "item 1" "item2" "item 3" "3" "*"; do
echo -n "'$x' is "
validate "$x" && echo "valid" || echo "invalid"
done
_contains () { # Check if space-separated list $1 contains line $2
echo "$1" | tr ' ' '\n' | grep -F -x -q "$2"
}
mylist="aa bb cc"
# Positive check
if _contains "${mylist}" "${myitem}"; then
echo "in list"
fi
# Negative check
if ! _contains "${mylist}" "${myitem}"; then
echo "not in list"
fi
: Needle "list" Seperator_opt
NeedleListSep()
{
if [ 3 -gt $# ];
then NeedleListSep "$1" "$2" " ";
else case "$3$2$3" in (*"$3$1$3"*) return 0;; esac; return 1;
fi;
}
演出晚了?以下非常简单的变体尚未明确提及。我使用
case
检查简单列表,这是一个通用的Bourne Shell习惯用法,不依赖任何外部或扩展:
haystack='a b c'
needle='b'
case " $haystack " in (*" $needle "*) :;; (*) false;; esac
- 请注意使用分隔符(此处:
)来正确划分模式:在SPC
的开头和结尾,同样在测试“$haystack”
时“$pinder”
- 如果
在$needle
中,则此语句返回$haystack
(true
),否则返回false$?=0
- 您还可以非常轻松地测试多个
$pinder
if(haystack.contains(needle1)){run1()}elif(haystack.contains(needle2)){run2()}else{run3()}
Test() { NeedleListSep "$1" "a b c" && echo found $1 || echo no $1; NeedleListSep "$1" "a,b,c" ',' && echo found $1 || echo no $1; NeedleListSep "$1" "a # b # c" ' # ' && echo found $1 || echo no $1; NeedleListSep "$1" "abc" '' && echo found $1 || echo no $1; } Test a Test z
Test
no no no found