unix 如何在Bash中使用正负索引获取子字符串

vmjh9lq9  于 2023-03-08  发布在  Unix
关注(0)|答案(5)|浏览(130)

我想要的很简单。给定一个字符串“this is my test string”,我想要返回从第2个位置到倒数第2个位置的子字符串。类似于:substring 'this is my test string' 1,-1。我知道我可以使用cut从字符串的开头得到一些东西,但是我不确定如何从字符串的结尾轻松地计算。

6yoyoihd

6yoyoihd1#

事实证明,我可以很容易地用awk来实现这一点,如下所示:
echo 'this is my test string' | awk '{ print substr( $0, 2, length($0)-2 ) }'

disho6za

disho6za2#

在awk、python、perl等语言中要更简洁,但这里有一种方法可以做到这一点:

#!/usr/bin/bash

msg="this is my test string"
start=2
len=$((${#msg} - ${start} - 2))

echo $len

echo ${msg:2:$len}

结果以is is my test stri为单位

ruarlubt

ruarlubt3#

只需使用纯bash即可完成此操作

$ string="i.am.a.stupid.fool.are.you?"
$ echo ${string:  2:$((${#string}-4))}
am.a.stupid.fool.are.yo
8tntrjer

8tntrjer4#

看,没有全局变量或fork(除了明显的printf),并且经过彻底测试:

substring()
{
    # Extract substring with positive or negative indexes
    # @param $1: String
    # @param $2: Start (default start of string)
    # @param $3: Length (default until end of string)

    local -i strlen="${#1}"
    local -i start="${2-0}"
    local -i length="${3-${#1}}"

    if [[ "$start" -lt 0 ]]
    then
        let start+=$strlen
    fi

    if [[ "$length" -lt 0 ]]
    then
        let length+=$strlen
        let length-=$start
    fi

    if [[ "$length" -lt 0 ]]
    then
        return
    fi

    printf %s "${1:$start:$length}"
}
pgccezyw

pgccezyw5#

你可以用pure bash * 来完成这个过程,当你想要一个相对于字符串末尾的端点时,* 的工作方式和Python这样的语言一样:

$ x='this is my test string'
 $ echo ${x:1:-1}  # Means "slice x beginning at index 1 to the end, excluding the last character"
 his is my test strin

这里有两点需要注意:
1.这与bash通常处理子字符串切片的方式不同(通常,第二个索引是一个 * length *,但是负的"length"被视为距离字符串末尾的 * offset *)
1.使用负索引作为起始位置也是合法的,但如果这样做,则必须在第一个冒号和负号之间包含一个空格(因为参数扩展中的:-已经被保留为表示"使用默认值",所以${x:-5}表示"如果设置了x并且不为空,则为x的值,否则为5的值",而${x: -5}表示"x的最后五个字符")。
这可以被打包成一个bash函数,完全按照你想要的方式工作(除了用一个空格替换1,-1中的,,这样它们就成了独立的参数;它 * 可以 * 使用逗号分隔的参数,但会增加复杂性),例如:

substring() {
  if (($#==3)); then
    # Start and length/end passed
    printf %s "${1:$2:$3}"  # No space needed when negative index from argument
  elif (($#==2)); then
    # Only start passed
    printf %s "${1:$2}"
  else
    printf "%s\n" "Usage: ${FUNCNAME} START [positive LENGTH or negative END]" >&2
    return 1
  fi
}

substring 'this is a test' 1 -1  # Echoes: his is a tes
echo
substring 'this is a test' -4    # Echoes: test

在线试用!
创建一个使用纯Python语义的"改进"版本(因此第三个参数总是被认为是偏移量,而不是长度)留给读者练习(这更烦人,因为负结束索引必须保持不转换,而正结束索引必须转换为长度或负偏移量,这可能导致级联要求将负开始索引转换为正索引;这是一个烂摊子,所以我保持上述函数简单)。

相关问题