如何在bash中检查字符串是否为-key值格式?

How to check if the string is in -key value format in bash?

提问人:ikhvjs 提问时间:9/11/2023 最后编辑:ikhvjs 更新时间:9/12/2023 访问量:108

问:

我想验证一个字符串,该字符串的格式必须为 。-key1 value1 -key2 value2

允许大写/小写字符、数字和下划线。like 或key-key_1-Key_name_2

可以是任何字符串,但不能是空字符串。所以,可能是 , .此外,可以使用双引号,我们从双引号中提取值。valuevaluevalue1-value1value"value1WithQuote"value1WithQuote

键值对的数量最多可以是 10 对。

我尝试使用下面的正则表达式,但它只检查第一个键

str="-mykey1 keyvalue1 -MY_KEY_2 keyvalue2"

regex="-([a-zA-Z]+)"
[[ $str =~ $regex ]] && echo "matched"

你能给我一些建议吗?

正则表达式 bash

评论

2赞 Uberhumus 9/11/2023
该值可以包含任何字符吗?具体可以包括“-”或“?
0赞 Justinas 9/11/2023
检查它是如何在PHP中完成的:stackoverflow.com/questions/36512378/...
0赞 Wiktor Stribiżew 9/11/2023
regex='^-[a-zA-Z]+([[:blank:]]-[a-zA-Z]+)*$'
0赞 Justinas 9/11/2023
@WiktorStribiżew 将失败-MY_KEY_2 keyvalye2
1赞 Ed Morton 9/11/2023
该字符串是如何填充的?很有可能它真的应该是一个数组而不是一个字符串。

答:

1赞 Freeman 9/11/2023 #1

我将遍历字符串并检查每个键值对,它使用修改后的正则表达式,其中匹配键并匹配值,循环继续,直到在字符串中找不到更多的键值对。-([a-zA-Z_0-9]+) ([^ ]+)([a-zA-Z_0-9]+)([^ ]+)while

看看这个

str="-mykey1 keyvalue1 -MY_KEY_2 keyvalue2"

regex="-([a-zA-Z_0-9]+) ([^ ]+)"
while [[ $str =~ $regex ]]; do
    key="${BASH_REMATCH[1]}"
    value="${BASH_REMATCH[2]}"
    echo "Key: $key, Value: $value"
    str="${str/${BASH_REMATCH[0]}/}"
done

更新

按照您的要求,我将从字符串中提取键值对并将它们存储在关联数组中(),我还对重复键、空值和键值对的最大数量进行额外检查,最后,它会打印提取的键值对!keyValuePairs

str="-mykey1 keyvalue1 -MY_KEY_2 keyvalue2"

#regex pattern for key-value pairs
regex="-([a-zA-Z0-9_]+)\s+([^-\s]+)"

#array to store the extracted key-value pairs
declare -A keyValuePairs

#iterate through the string and extract key-value pairs
while [[ $str =~ $regex ]]; do
  key="${BASH_REMATCH[1]}"
  value="${BASH_REMATCH[2]}"
  
  #checking if the key already exists
  if [[ ${keyValuePairs[$key]+_} ]]; then
    echo "Duplicate key: $key"
    exit 1
  fi

  #checking if the value is empty
  if [[ -z $value ]]; then
    echo "Empty value for key: $key"
    exit 1
  fi
  
  #storing the key-value pair in the array
  keyValuePairs[$key]=$value
  
  #removing the matched key-value pair from the string
  str=${str/${BASH_REMATCH[0]}/}
done

#checking the number of key-value pairs
numPairs=${#keyValuePairs[@]}
if (( numPairs > 10 )); then
  echo "Too many key-value pairs. Maximum is 10."
  exit 1
fi

#printing the extracted key-value pairs
for key in "${!keyValuePairs[@]}"; do
  value="${keyValuePairs[$key]}"
  echo "Key: $key, Value: $value"
done

评论

1赞 ikhvjs 9/11/2023
谢谢。我更新了我的任务以提到值不能是空字符串。你也能处理这种情况吗?所以 value 也可以是 “-value1”
1赞 Wiktor Stribiżew 9/11/2023 #2

你可以使用

str="-mykey1 keyvalue1 -MY_KEY_2 keyvalue2"
regex='^-[a-zA-Z0-9_]+( [a-zA-Z0-9]+)?( -[a-zA-Z0-9_]+( [a-zA-Z0-9_]+)?){0,9}$'
[[ $str =~ $regex ]] && echo "matched"

细节

  • ^- 字符串的开头
  • -- 连字符
  • [a-zA-Z0-9_]+- 一个或多个字母/数字/下划线
  • ( [a-zA-Z0-9]+)?- 可选出现以下情况:
    • - 一个空格
    • [a-zA-Z0-9]+- 一个或多个字母/数字
  • ( -[a-zA-Z0-9_]+( [a-zA-Z0-9_]+)?)*- 空格出现次数为零次或多次 + 与上述相同的模式
  • $- 字符串末尾。

评论

0赞 ikhvjs 9/11/2023
谢谢。我更新了我的问题。键值对的数量最多可以是 10 对。因此,value 不能是空字符串,它可以是“-value1”
0赞 Wiktor Stribiżew 9/11/2023
@ikhvjs 只需将零件设置为可选,即 并将最后一个替换为设置附加选项数量的限制。<space>[a-zA-Z0-9_]+( [a-zA-Z0-9_]+)?*{0,9}
1赞 Ed Morton 9/11/2023 #3

很有可能你的起始值实际上应该被填充为数组而不是字符串,但如果你的值都不能包含空格,这里是如何将其转换为数组并立即使用它:str

$ cat tst.sh
#!/usr/bin/env bash

str="-mykey1 keyvalue1 -MY_KEY_2 keyvalue2 -this:that"

read -r -a arr <<<"$str"

regex='^-[[:alnum:]_]+$'
for (( i=0; i<${#arr[@]}; i+=2 )); do
    key="${arr[i]}"
    val="${arr[((i+1))]}"
    if [[ $key =~ $regex ]]; then
        echo "Key \"$key\" matched"
    else
        echo "Key \"$key\" did not match"
    fi
    if [[ -n $val ]]; then
        echo "Val \"$val\" is non-empty"
    else
        echo "Val \"$val\" is empty"
    fi
done

$ ./tst.sh
Key "-mykey1" matched
Val "keyvalue1" is non-empty
Key "-MY_KEY_2" matched
Val "keyvalue2" is non-empty
Key "-this:that" did not match
Val "" is empty

如前所述,上面假设您的值都不包含空格,否则以这种方式填充数组将失败。


编辑:说明为什么你应该将参数存储在数组而不是字符串中:

$ cat tst.sh
#!/usr/bin/env bash

args=()
for i in "$@"; do
    args+=( "$i" )
done

for (( i=0; i<${#args[@]}; i++ )); do
    printf 'Argument #%d = "%s"\n' "$i" "${args[i]}"
done

$ ./tst.sh -key1 'this -foo that' -key2 value2
Argument #0 = "-key1"
Argument #1 = "this -foo that"
Argument #2 = "-key2"
Argument #3 = "value2"

第一个循环是将参数值存储在数组中,第二个循环是访问它们的值。

我假设您有理由希望存储参数值,否则您可以在上面的第二个循环中执行并删除第一个循环。for arg in "$@"