【问题标题】:number of tokens in bash variablebash 变量中的标记数
【发布时间】:2010-10-12 22:24:58
【问题描述】:

我如何知道 bash 变量中的标记数(空格分隔的标记) - 或者至少,它是一个还是多个。

【问题讨论】:

    标签: bash split


    【解决方案1】:

    $# 扩展将告诉您变量/数组中的元素数量。如果您使用的 bash 版本高于 2.05 左右,您可以:

    VAR='some string with words'
    VAR=( $VAR )
    echo ${#VAR[@]}
    

    这有效地将字符串沿空格(这是默认分隔符)拆分为一个数组,然后计算数组的成员数。

    编辑:

    当然,这会将变量重新转换为数组。如果您不想这样,请使用不同的变量名称或将变量重新转换为字符串:

    VAR="${VAR[*]}"
    

    【讨论】:

    • CAVEAT:如果 $VAR 包含一个恰好是有效 glob 的字符串,则结果将出乎意料,因为会发生路径名扩展;试试VAR='* string with words'
    • 什么鬼。请使用VAR=( "${VAR[@]}" ),它会保留"a b""a" "b" 等元素之间的连接。
    【解决方案2】:

    我不明白为什么人们一直在使用那些过于复杂的 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 $# )
    

    如果我们想避免使用 subshel​​l,事情就会变得很糟糕

    howmany() {
        case $- in *f*) set -- $1;; *) set -f; set -- $1; set +f;; esac
        echo $#
    }
    

    这两个必须使用 WITH 引号,例如howmany "one two three" 返回3

    【讨论】:

    • 好一个。简单且没有副作用(当然,除了声明一个新函数)。另外,作为奖励,您似乎发现了一个 geshi(?) bash 渲染器错误。
    • 为什么要避免使用 subshel​​l?只是效率?顺便说一句,我不知道如果您将函数体包含在(..) 中以在子shell 中运行,您可以省略{...} - 很高兴知道。
    • @mklement0:是的,只是效率。所以这是一个不必要的优化,因为 howmany 的唯一用例可能是调试。
    • @mklement0:是的,能够只写myfun() ( ... ) 有点好,但我觉得不允许裸myfun() cmd args; 有点不一致。另请注意,还可以声明myfun() { ... } > "$foo"(也带有圆括号)用于调用时重定向,这很花哨。
    • @JoSo:很高兴了解呼叫时间重定向功能,谢谢;我想知道它有多大用处。
    【解决方案3】:
    set VAR='hello world'
    echo $VAR | wc -w
    

    这里是你可以检查的方法。

    if [ `echo $VAR | wc -w` -gt 1 ] 
    then
        echo "Hello"
    fi
    

    【讨论】:

    • 很好,但我建议你 (a) 双引号 $VAR,否则该值将受到路径名扩展和 (b) 使用当前的 bash 功能;即: - 将计数存储在变量中(修剪空格):count=$(( $(wc -w <<<"$VAR") )); - 行动,如果计数 > 1:if (( $(wc -w <<<"$VAR") > 1 )); then echo "HELLO"; fi
    【解决方案4】:

    简单方法:

    $ VAR="a b c d"
    $ set $VAR
    $ echo $#
    4
    

    【讨论】:

    • 2 个问题:(a) 在接受的答案中,$VAR 中恰好是有效 glob(例如,*)的令牌将扩展为匹配的文件名。 (b) 如果第一个(一个或多个)令牌恰好是有效的 set 选项 - 例如VAR="-e" - 它们会被这样解释并导致意想不到的结果;您可以使用set -- $VAR 来防止这种情况发生。
    【解决方案5】:

    计数:

    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"
    

    【讨论】:

    • 这假定有规则的间距,即两个单词之间有两个空格会给出错误的结果(无论如何,结果都会偏离一个——fencepost 错误)。
    【解决方案6】:

    要获得强大的便携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 *' '*|*'&lt;tab&gt;'*|*'&lt;nl&gt;'*) echo yes;; esac。将&lt;tab&gt;&lt;nl&gt; 替换为真正的制表符和真正的换行符,我不能将它们放在评论中。
    • @JoSo:很酷,谢谢。实际上有一种方法可以创建这样的字符。通过非文字在 bash 中:$'\t'$'\n'
    【解决方案7】:

    不确定这是否正是您的意思,但是:

    $# = 传递给 bash 脚本的参数数量

    否则你可能会寻找类似man wc的东西

    【讨论】:

    • 冗余且不回答具体问题
    猜你喜欢
    • 2020-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    • 2018-06-15
    相关资源
    最近更新 更多