使用 bash/cut/split 提取字符串的一部分

我有一条这样的线:

/var/cpanel/users/joebloggs:DNS9=domain.example

我需要从这个字符串中提取用户名(joebloggs)并将其存储在一个变量中。

字符串的格式总是相同的除了 joebloggsdomain.example,所以我认为字符串可以拆分两次使用 cut

第一个拆分将被 :拆分,我们将把第一部分存储在一个变量中以传递给第二个拆分函数。

第二个拆分将被 /拆分,并将最后一个单词(joebloggs)存储到一个变量中

我知道如何在 PHP 中使用数组和分割来实现这一点,但是我在 bash 中有点迷失了。

462694 次浏览

定义如下函数:

getUserName() {
echo $1 | cut -d : -f 1 | xargs basename
}

并将字符串作为参数传递:

userName=$(getUserName "/var/cpanel/users/joebloggs:DNS9=domain.example")
echo $userName

使用一个 Awk:

... | awk -F '[/:]' '{print $5}'

也就是说,使用 /:作为字段分隔符,用户名始终位于字段5中。

将其存储在变量中:

username=$(... | awk -F '[/:]' '{print $5}')

使用 sed的一个更灵活的实现,它不需要用户名作为字段5:

... | sed -e s/:.*// -e s?.*/??

也就是说,从 :及以后删除所有内容,然后删除所有内容,直到最后一个 /sed可能也比 awk快,所以这个选择肯定更好。

使用单个 sed

echo "/var/cpanel/users/joebloggs:DNS9=domain.example" | sed 's/.*\/\(.*\):.*/\1/'

要在 bash 中使用参数展开从这个字符串中提取 joebloggs,不需要任何额外的进程..。

MYVAR="/var/cpanel/users/joebloggs:DNS9=domain.example"


NAME=${MYVAR%:*}  # retain the part before the colon
NAME=${NAME##*/}  # retain the part after the last slash
echo $NAME

不依赖于 joebloggs在路径的特定深度。


摘要

概述了几种参数扩展方式,供同行参考。

${MYVAR#pattern}     # delete shortest match of pattern from the beginning
${MYVAR##pattern}    # delete longest match of pattern from the beginning
${MYVAR%pattern}     # delete shortest match of pattern from the end
${MYVAR%%pattern}    # delete longest match of pattern from the end

因此,#表示从头开始匹配(想想一个注释行) ,而 %表示从头开始匹配。一个实例表示最短,两个实例表示最长。

您可以使用数字根据位置获得子字符串:

${MYVAR:3}   # Remove the first three chars (leaving 4..end)
${MYVAR::3}  # Return the first three characters
${MYVAR:3:5} # The next five characters after removing the first 3 (chars 4-9)

还可以使用以下方法替换特定的字符串或模式:

${MYVAR/search/replace}

pattern的格式与文件名匹配相同,因此 *(任何字符)都很常见,后面常常跟着特定的符号,如 /.

例子:

给定一个变量,比如

MYVAR="users/joebloggs/domain.example"

删除保留文件名的路径(所有字符直到斜杠) :

echo ${MYVAR##*/}
domain.example

删除文件名,留下路径(删除最后一个 /之后的最短匹配) :

echo ${MYVAR%/*}
users/joebloggs

只获取文件扩展名(删除上一节前的所有内容) :

echo ${MYVAR##*.}
example

注意: 要执行两个操作,您不能合并它们,但必须赋值给一个中间变量。因此,要获得没有路径或扩展名的文件名:

NAME=${MYVAR##*/}      # remove part before last slash
echo ${NAME%.*}        # from the new var remove the part after the last period
domain

Sed 呢? 它将在单个命令中工作:

sed 's#.*/\([^:]*\).*#\1#' <<<$string
  • 由于字符串中包含 /,因此正则表达式除法器使用的是 #,而不是 /
  • .*/获取直到最后一个反斜杠的字符串。
  • \( .. \)代表捕获组,这里是 \([^:]*\)
    • [^:]表示除冒号之外的任何字符,而 *表示零或更多。
  • .*表示其余的线路。
  • \1意味着替换在第一个(也是唯一的)捕获组中找到的内容。

下面是匹配字符串和正则表达式的分解:

        /var/cpanel/users/           joebloggs  :DNS9=domain.example joebloggs
sed 's#.*/                          \([^:]*\)   .*              #\1       #'

我知道我来得有点晚了,而且已经有很好的答案了,但是这是我做这件事的方法。

DIR="/var/cpanel/users/joebloggs:DNS9=domain.example"
echo ${DIR} | rev | cut -d'/' -f 1 | rev | cut -d':' -f1

我喜欢使用带有 -F 参数的不同分隔符将 awk 链接在一起。首先,在 /使用者/上拆分字符串,然后在 :上拆分字符串

txt="/var/cpanel/users/joebloggs:DNS9=domain.com"
echo $txt | awk -F"/users/" '{print$2}' | awk -F: '{print $1}'

$2 给出分隔符后面的文本,1元给出分隔符前面的文本。