【发布时间】:2010-10-12 22:24:58
【问题描述】:
我如何知道 bash 变量中的标记数(空格分隔的标记) - 或者至少,它是一个还是多个。
【问题讨论】:
我如何知道 bash 变量中的标记数(空格分隔的标记) - 或者至少,它是一个还是多个。
【问题讨论】:
$# 扩展将告诉您变量/数组中的元素数量。如果您使用的 bash 版本高于 2.05 左右,您可以:
VAR='some string with words'
VAR=( $VAR )
echo ${#VAR[@]}
这有效地将字符串沿空格(这是默认分隔符)拆分为一个数组,然后计算数组的成员数。
编辑:
当然,这会将变量重新转换为数组。如果您不想这样,请使用不同的变量名称或将变量重新转换为字符串:
VAR="${VAR[*]}"
【讨论】:
$VAR 包含一个恰好是有效 glob 的字符串,则结果将出乎意料,因为会发生路径名扩展;试试VAR='* string with words'。
VAR=( "${VAR[@]}" ),它会保留"a b" 和"a" "b" 等元素之间的连接。
我不明白为什么人们一直在使用那些过于复杂的 bashism。几乎总是有一个直截了当的、没有害羞的解决方案。
howmany() { echo $#; }
myvar="I am your var"
howmany $myvar
这使用了 shell 内置的分词器,所以没有差异。
这是一个相关的问题:
myvar='*'
echo $myvar
echo "$myvar"
set -f
echo $myvar
echo "$myvar"
请注意,@guns 使用 bash 数组的解决方案具有相同的问题。
以下是解决问题的(据说)超级强大的版本:
howmany() ( set -f; set -- $1; echo $# )
如果我们想避免使用 subshell,事情就会变得很糟糕
howmany() {
case $- in *f*) set -- $1;; *) set -f; set -- $1; set +f;; esac
echo $#
}
这两个必须使用 WITH 引号,例如howmany "one two three" 返回3
【讨论】:
(..) 中以在子shell 中运行,您可以省略{...} - 很高兴知道。
myfun() ( ... ) 有点好,但我觉得不允许裸myfun() cmd args; 有点不一致。另请注意,还可以声明myfun() { ... } > "$foo"(也带有圆括号)用于调用时重定向,这很花哨。
set VAR='hello world'
echo $VAR | wc -w
这里是你可以检查的方法。
if [ `echo $VAR | wc -w` -gt 1 ]
then
echo "Hello"
fi
【讨论】:
$VAR,否则该值将受到路径名扩展和 (b) 使用当前的 bash 功能;即: - 将计数存储在变量中(修剪空格):count=$(( $(wc -w <<<"$VAR") )); - 行动,如果计数 > 1:if (( $(wc -w <<<"$VAR") > 1 )); then echo "HELLO"; fi
简单方法:
$ VAR="a b c d"
$ set $VAR
$ echo $#
4
【讨论】:
$VAR 中恰好是有效 glob(例如,*)的令牌将扩展为匹配的文件名。 (b) 如果第一个(一个或多个)令牌恰好是有效的 set 选项 - 例如VAR="-e" - 它们会被这样解释并导致意想不到的结果;您可以使用set -- $VAR 来防止这种情况发生。
计数:
sentence="This is a sentence, please count the words in me."
words="${sentence//[^\ ]} "
echo ${#words}
检查:
sentence1="Two words"
sentence2="One"
[[ "$sentence1" =~ [\ ] ]] && echo "sentence1 has more than one word"
[[ "$sentence2" =~ [\ ] ]] && echo "sentence2 has more than one word"
【讨论】:
要获得强大的便携sh 解决方案,请参阅@JoSo's functions 使用set -f。
(用于回答(仅)“是否至少有 1 个空格?”问题的简单 bash-only 解决方案;注意:也将匹配前导和尾随空格,这与下面的 awk 解决方案不同:
[[ $v =~ [[:space:]] ]] && echo "\$v has at least 1 whitespace char."
)
这是一个强大的基于 awk 的 bash 解决方案(由于调用了外部实用程序,效率较低,但在许多实际场景中可能无关紧要):
# Functions - pass in a quoted variable reference as the only argument.
# Takes advantage of `awk` splitting each input line into individual tokens by
# whitespace; `NF` represents the number of tokens.
# `-v RS=$'\3'` ensures that even multiline input is treated as a single input
# string.
countTokens() { awk -v RS=$'\3' '{print NF}' <<<"$1"; }
hasMultipleTokens() { awk -v RS=$'\3' '{if(NF>1) ec=0; else ec=1; exit ec}' <<<"$1"; }
# Example: Note the use of glob `*` to demonstrate that it is not
# accidentally expanded.
v='I am *'
echo "\$v has $(countTokens "$v") token(s)."
if hasMultipleTokens "$v"; then
echo "\$v has multiple tokens."
else
echo "\$v has just 1 token."
fi
【讨论】:
hasMultipleTokens。如果您认为空白是默认设置(空格、制表符、换行符或 0x20,0x09,0x10),请尝试 case $1 in *' '*|*'<tab>'*|*'<nl>'*) echo yes;; esac。将<tab> 和<nl> 替换为真正的制表符和真正的换行符,我不能将它们放在评论中。
$'\t' 和 $'\n'。
【讨论】: