152

我有一个这样的字符串:

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

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

字符串的格式将始终相同,但joebloggsdomain.com认为字符串可以使用cut

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

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

我知道如何在 php 中使用数组和拆分来做到这一点,但我有点迷失在 bash 中。

4

6 回答 6

406

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

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

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.com" 

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

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

删除文件名,保留路径(删除 last 之后的最短匹配项/):

echo ${MYVAR%/*}
users/joebloggs

只获取文件扩展名(在最后一个句点之前删除所有):

echo ${MYVAR##*.}
com

注意:要执行两个操作,您不能将它们组合起来,而必须分配给一个中间变量。所以要获取没有路径或扩展名的文件名:

NAME=${MYVAR##*/}      # remove part before last slash
echo ${NAME%.*}        # from the new var remove the part after the last period
domain
于 2013-10-20T21:16:01.730 回答
52

定义一个这样的函数:

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

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

userName=$(getUserName "/var/cpanel/users/joebloggs:DNS9=domain.com")
echo $userName
于 2013-10-20T19:59:00.130 回答
24

赛德呢?这将在一个命令中起作用:

sed 's#.*/\([^:]*\).*#\1#' <<<$string
  • #用于正则表达式分隔符,而不是因为/字符串/在其中。
  • .*/将字符串抓取到最后一个反斜杠。
  • \( .. \)标记一个捕获组。这是\([^:]*\).
    • [^:]表示任何字符 _except 冒号,表示*零个或多个。
  • .*表示该行的其余部分。
  • \1表示替换在第一个(也是唯一一个)捕获组中找到的内容。这是名字。

这是将字符串与正则表达式匹配的细分:

        /var/cpanel/users/           joebloggs  :DNS9=domain.com joebloggs
sed 's#.*/                          \([^:]*\)   .*              #\1       #'
于 2014-12-24T20:54:11.240 回答
13

使用单个 awk:

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

也就是说,使用/或作为字段分隔符:,用户名总是在字段 5 中。

要将其存储在变量中:

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

一个更灵活的实现sed不需要用户名是字段 5:

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

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

于 2013-10-20T20:08:58.143 回答
11

使用单个 sed

echo "/var/cpanel/users/joebloggs:DNS9=domain.com" | sed 's/.*\/\(.*\):.*/\1/'
于 2013-10-20T21:08:06.080 回答
0

我知道我参加聚会有点晚了,而且已经有了很好的答案,但这是我做这种事情的方法。

DIR="/var/cpanel/users/joebloggs:DNS9=domain.com"
echo ${DIR} | rev | cut -d'/' -f 1 | rev | cut -d':' -f1
于 2022-01-17T05:57:24.993 回答