在 Unix shell 中提取子字符串的最简单方法?

在 Unix shell 中提取子字符串的最简单方法?

在 Unix shell 中提取子字符串的最简单方法是什么(使用正则表达式)?

简单意味着:

  • 功能较少
  • 更少的选择
  • 学习较少

更新

我意识到正则表达式本身与简单性相冲突,因此我选择了最简单的正则表达式cut作为答案。很抱歉问题模糊。我更改了标题以更准确地表示此问答的当前状态。

答案1

cut可能会有用:

$ echo hello | cut -c1,3
hl
$ echo hello | cut -c1-3
hel
$ echo hello | cut -c1-4
hell
$ echo hello | cut -c4-5
lo

Shell Builtins 也适用于此,这里有一个示例脚本:

#!/bin/bash
# Demonstrates shells built in ability to split stuff.  Saves on
# using sed and awk in shell scripts. Can help performance.

shopt -o nounset
declare -rx       FILENAME=payroll_2007-06-12.txt

# Splits
declare -rx   NAME_PORTION=${FILENAME%.*}     # Left of .
declare -rx      EXTENSION=${FILENAME#*.}     # Right of .
declare -rx           NAME=${NAME_PORTION%_*} # Left of _
declare -rx           DATE=${NAME_PORTION#*_} # Right of _
declare -rx     YEAR_MONTH=${DATE%-*}         # Left of _
declare -rx           YEAR=${YEAR_MONTH%-*}   # Left of _
declare -rx          MONTH=${YEAR_MONTH#*-}   # Left of _
declare -rx            DAY=${DATE##*-}        # Left of _

clear

echo "  Variable: (${FILENAME})"
echo "  Filename: (${NAME_PORTION})"
echo " Extension: (${EXTENSION})"
echo "      Name: (${NAME})"
echo "      Date: (${DATE})"
echo "Year/Month: (${YEAR_MONTH})"
echo "      Year: (${YEAR})"
echo "     Month: (${MONTH})"
echo "       Day: (${DAY})"

输出:

  Variable: (payroll_2007-06-12.txt)
  Filename: (payroll_2007-06-12)
 Extension: (txt)
      Name: (payroll)
      Date: (2007-06-12)
Year/Month: (2007-06)
      Year: (2007)
     Month: (06)
       Day: (12)

并且根据上面的 Gnudif,当事情变得非常艰难时,总会有 sed/awk/perl。

答案2

Unix shell 传统上不内置正则表达式支持。Bash 和 Zsh 都有,因此如果您使用=~运算符将​​字符串与正则表达式进行比较,则:

您可以从$BASH_REMATCHbash 中的数组中获取子字符串。

在 Zsh 中,如果BASH_REMATCH设置了 shell 选项,则值位于$BASH_REMATCH数组中,否则位于$MATCH/$match绑定的变量对中(一个标量,另一个数组)。如果RE_MATCH_PCRE设置了选项,则使用 PCRE 引擎,否则使用系统正则表达式库,进行扩展正则表达式语法匹配,就像 bash 一样。

因此,最简单的方法是:如果你使用 bash:

if [[ "$variable" =~ unquoted.*regex ]]; then
  matched_portion="${BASH_REMATCH[0]}"
  first_substring="${BASH_REMATCH[1]}"
fi

如果您不使用 Bash 或 Zsh,情况会变得更加复杂,因为您需要使用外部命令。

答案3

更新答案-适用于(所有?)POSIX 兼容expr

也考虑一下/usr/bin/expr

$ expr hello : '.\(...\)'
ell

$ expr hello : 'hel'
3

$ expr hello : '.*el'
3

$ expr hello : '.*\(el\)'
el

原始答案-适用于 GNUexpr

也考虑一下/usr/bin/expr

$ expr substr hello 2 3
ell

您还可以将模式与字符串的开头进行匹配。

$ expr match hello h
1

$ expr match hello hell
4

$ expr match hello e
0

$ expr match hello 'h.*o'
5

$ expr match hello 'h.*l'
4

$ expr match hello 'h.*e'
2

答案4

# $1 string
# $2 index of first char
# $3 index of last char
substr()
{
    subStrPatternPrefix=".\\{$2\\}"
    subStrPatternMatch="\\(.\\{$(( $3 - $2 + 1 ))\\}\\)"
    expr "$1" : "$subStrPatternPrefix$subStrPatternMatch"
}

使用示例:

string="Hello World!"
s1=$( substr "$string" 0 4 )
s2=$( substr "$string" 6 10 )
s3=$( substr "$string" 11 11 )

echo "$s1"
echo "$s2"
echo "$s3"

输出:

Hello
World
!

相关内容