【问题标题】:How to get the last character of a string in a shell?如何在shell中获取字符串的最后一个字符?
【发布时间】:2013-07-06 17:52:37
【问题描述】:

我写了以下几行来获取字符串的最后一个字符:

str=$1
i=$((${#str}-1))
echo ${str:$i:1}

它适用于abcd/

$ bash last_ch.sh abcd/
/

不适用于abcd*

$ bash last_ch.sh abcd*
array.sh assign.sh date.sh dict.sh full_path.sh last_ch.sh

列出当前文件夹中的文件

【问题讨论】:

    标签: string bash shell


    【解决方案1】:

    到目前为止,每个答案都暗示问题中的“shell”一词等同于 Bash。

    这是在标准的 Bourne shell 中如何做到这一点的:

    printf "%s" "$str" | tail -c 1
    

    【讨论】:

    • echo -n 由 user5394399 提出,避免$str 包含特殊格式字符时出现问题。
    • -n 开关是一个 bashism。它不能在标准的 Bourne shell 中作为破折号等工作......这是我回答的重点。
    • 不完全是 bashism,但 POSIX 承认它是实现定义的(“如果第一个操作数是 -n,或者如果任何操作数包含 字符,则结果是实现定义的” )。你的答案可以改用printf "%s" "$str" | ... :-)。
    【解决方案2】:

    对于任何对纯 POSIX 方法感兴趣的人:

    https://github.com/spiralofhope/shell-random/blob/master/live/sh/scripts/string-fetch-last-character.sh

    #!/usr/bin/env  sh
    
    string_fetch_last_character() {
      length_of_string=${#string}
      last_character="$string"
      i=1
      until [ $i -eq "$length_of_string" ]; do
        last_character="${last_character#?}"
        i=$(( i + 1 ))
      done
    
      printf  '%s'  "$last_character"
    }
    
    
    string_fetch_last_character  "$string"
    

    【讨论】:

    【解决方案3】:

    对于portability 你可以说"${s#"${s%?}"}":

    #!/bin/sh
    m=bzzzM n=bzzzN
    for s in \
        'vv'  'w'   ''    'uu  ' ' uu ' '  uu' / \
        'ab?' 'a?b' '?ab' 'ab??' 'a??b' '??ab' / \
        'cd#' 'c#d' '#cd' 'cd##' 'c##d' '##cd' / \
        'ef%' 'e%f' '%ef' 'ef%%' 'e%%f' '%%ef' / \
        'gh*' 'g*h' '*gh' 'gh**' 'g**h' '**gh' / \
        'ij"' 'i"j' '"ij' "ij'"  "i'j"  "'ij"  / \
        'kl{' 'k{l' '{kl' 'kl{}' 'k{}l' '{}kl' / \
        'mn$' 'm$n' '$mn' 'mn$$' 'm$$n' '$$mn' /
    do  case $s in
        (/) printf '\n' ;;
        (*) printf '.%s. ' "${s#"${s%?}"}" ;;
        esac
    done
    

    输出:

    .v. .w. .. . . . . .u. 
    .?. .b. .b. .?. .b. .b. 
    .#. .d. .d. .#. .d. .d. 
    .%. .f. .f. .%. .f. .f. 
    .*. .h. .h. .*. .h. .h. 
    .". .j. .j. .'. .j. .j. 
    .{. .l. .l. .}. .l. .l. 
    .$. .n. .n. .$. .n. .n. 
    

    【讨论】:

      【解决方案4】:
      expr $str : '.*\(.\)'
      

      或者

      echo ${str: -1}
      

      【讨论】:

        【解决方案5】:

        这就是您需要引用变量的原因之一:

        echo "${str:$i:1}"
        

        否则,bash 会扩展变量,在这种情况下会在打印输出之前进行 globbing。最好将参数引用到脚本中(如果您有匹配的文件名):

        sh lash_ch.sh 'abcde*'
        

        另请参阅bash reference manual 中的扩展顺序。变量在文件名扩展之前被扩展。

        要获取最后一个字符,您应该使用 -1 作为索引,因为负索引从字符串末尾开始计数:

        echo "${str: -1}"
        

        冒号后的空格 (:) 是必需的。

        如果没有空格,这种方法就行不通。

        【讨论】:

        • 顺便说一句,负索引从右开始计数,所以"${1: -1}" 就足够了。
        • 您应该作为正式解决方案回复,而不是在 cmets 中。
        • 仅供参考:您也可以在 echo "${str:$((${#str}-1)):1}" 的“单行”中执行此操作。这也允许您更改返回的尾随字符。在 bash v4.1.0(1) 中对我有用
        • @choroba 的回答:注意该死的空间!这总是让我绊倒:"${1:-1} 不起作用”!
        【解决方案6】:

        试试:

        "${str:$((${#str}-1)):1}"
        

        例如:

        someone@mypc:~$ str="A random string*"; echo "$str"
        A random string*
        someone@mypc:~$ echo "${str:$((${#str}-1)):1}"
        *
        someone@mypc:~$ echo "${str:$((${#str}-2)):1}"
        g
        

        【讨论】:

          【解决方案7】:

          我知道这是一个非常古老的线程,但没有人提到对我来说哪个是最干净的答案:

          echo -n $str | tail -c 1
          

          请注意,-n 只是这样 echo 在末尾不包含换行符。

          【讨论】:

          • 甚至没有比 ${str: -1} 更干净
          • 它更简洁,因为它不依赖于 bash-ism,因此它可以与任何 Posix shell 一起使用。
          • 什么是最“bashist”? "${str: -1}" 还有……什么最干净? "${str: -1}" Bash 是最好的选择! :-)
          • 对于任何试图在大文件上打印最后一个字符的人来说,这对我来说是成功的:cat user/folder/file.json | tail -c 1 可以将 1 替换为要打印的字符数。
          【解决方案8】:

          单行:

          ${str:${#str}-1:1}
          

          现在:

          echo "${str:${#str}-1:1}"
          

          【讨论】:

          • 为什么要用两对括号?此外,从 4.2 开始,您可以使用负偏移量,如 quickshiftin 的回答所示:echo "${str: -1}" 就足够了(注意:- 之间的空间)。
          • 两对括号用于算术运算
          • 没有。请参阅the relevant part of the manual,您将在其中阅读:lengthoffset 是算术表达式(请参阅 Shell Arithmetic);因此,您已经在 shell 算术中,根本不需要任何括号。此外,如果你说的是真的,那么用$((...))进行算术扩展会更合乎逻辑。
          • @gniourf_gniourf 你是对的!我现在明白你之前的问题了。答案已更新
          【解决方案9】:

          另一种使用 awk 脚本的解决方案:

          最后 1 个字符:

          echo $str | awk '{print substr($0,length,1)}'
          

          最后 5 个字符:

          echo $str | awk '{print substr($0,length-5,5)}'
          

          【讨论】:

          • 不是 OP 要求的,但这是我发现与文件一起使用的最佳解决方案。大多数其他方法都无法将文件添加到其中,例如:cat file | awk '{print substr($0,length,1)}'Thanks!
          【解决方案10】:
          echo $str | cut -c $((${#str}))
          

          是个好办法

          【讨论】:

            【解决方案11】:

            根据@perreal,引用变量很重要,但因为我在找到解决cmets 手头问题的更简单方法之前将这篇文章读了5 遍...

            str='abcd/'
            echo "${str: -1}"
            

            输出:/

            str='abcd*'
            echo "${str: -1}"
            

            输出:*

            感谢所有参与上述活动的人;我在整个帖子中适当地添加了 +1!

            【讨论】:

            • 注意:注意${std: -1} 里面的空格,没有空格就不行。我遇到了这个,发现${std:~0} 也可以工作(有或没有空格)。不确定这是否是记录在案的行为,但我没有费心去查找它。
            • 已记录在案。 man bash 说:以 - 开头的算术表达式必须用空格与前面的 : 分隔,以区别于使用默认值扩展
            • 太棒了,谢谢分享。虽然 BASH 手册页读起来几乎是压倒性的,但我已经去过那里好几次了。我认为他们可以围绕 shell 脚本开设一门大学课程,哈哈。
            • 当尝试将检索到的字符分配给变量时,此解决方案在 .sh 脚​​本中不起作用。例如declare LAST=$(echo "${str: -1}") 这将导致讨厌的红色条显示从:开始的语法错误:
            • 如果编辑器语法检查不喜欢那个空格试试${str:0-1}
            猜你喜欢
            • 2011-07-07
            • 2011-08-17
            • 2011-03-10
            • 2011-02-10
            • 1970-01-01
            • 2011-11-18
            • 2021-09-18
            相关资源
            最近更新 更多