我想要的很简单。给定一个字符串“this is my test string”,我想要返回从第2个位置到倒数第2个位置的子字符串。类似于:substring 'this is my test string' 1,-1。我知道我可以使用cut从字符串的开头得到一些东西,但是我不确定如何从字符串的结尾轻松地计算。
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}"
}
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
5条答案
按热度按时间6yoyoihd1#
事实证明,我可以很容易地用awk来实现这一点,如下所示:
echo 'this is my test string' | awk '{ print substr( $0, 2, length($0)-2 ) }'
disho6za2#
在awk、python、perl等语言中要更简洁,但这里有一种方法可以做到这一点:
结果以
is is my test stri
为单位ruarlubt3#
只需使用纯
bash
即可完成此操作8tntrjer4#
看,没有全局变量或fork(除了明显的
printf
),并且经过彻底测试:pgccezyw5#
你可以用pure bash * 来完成这个过程,当你想要一个相对于字符串末尾的端点时,* 的工作方式和Python这样的语言一样:
这里有两点需要注意:
1.这与bash通常处理子字符串切片的方式不同(通常,第二个索引是一个 * length *,但是负的"length"被视为距离字符串末尾的 * offset *)
1.使用负索引作为起始位置也是合法的,但如果这样做,则必须在第一个冒号和负号之间包含一个空格(因为参数扩展中的
:-
已经被保留为表示"使用默认值",所以${x:-5}
表示"如果设置了x
并且不为空,则为x
的值,否则为5
的值",而${x: -5}
表示"x
的最后五个字符")。这可以被打包成一个
bash
函数,完全按照你想要的方式工作(除了用一个空格替换1,-1
中的,
,这样它们就成了独立的参数;它 * 可以 * 使用逗号分隔的参数,但会增加复杂性),例如:在线试用!
创建一个使用纯Python语义的"改进"版本(因此第三个参数总是被认为是偏移量,而不是长度)留给读者练习(这更烦人,因为负结束索引必须保持不转换,而正结束索引必须转换为长度或负偏移量,这可能导致级联要求将负开始索引转换为正索引;这是一个烂摊子,所以我保持上述函数简单)。