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


121

我有一个像这样的字符串:

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

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

字符串的格式将永远伴随着的例外,同joebloggsdomain.com,所以我想字符串可以分割使用两次cut

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

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

我知道如何使用数组和拆分在php中执行此操作,但我对bash有点迷失。

Answers:


332

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

我不确定这是否支持grep的创造性使用,但可以尝试使用VAR = / here / is / a / path:with / a / colon / inside:DNS9 = domain.com
rici

2
甜!它是在执行外壳程序内完成的,因此比使用其他命令的速度更快。
stolsvik 2014年

3
@Fadi您必须将通配符切换到冒号之前,并使用#代替%。如果只想要最后一个冒号${MYVAR##*:}之后的部分,请使用${MYVAR#*:}
beroe

4
朋友,您不知道我已经回来多少次了。谢谢!
乔尔·B

1
好答案!问题:如果我的模式是一个变量,我会像这样${RET##*$CHOP}或这样${RET##*CHOP}(或其他方式)键入吗?编辑:似乎是前者${RET##*$CHOP}
Ctrl S

43

定义一个这样的函数:

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

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

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

1
这个答案帮助我实现了来到这里的目的。没有可接受的答案,这是我为简单而投票的答案。
哈珀维尔2014年

1
我在上述命令中唯一要做的更正就是删除':',就像这样echo $1 | cut -d -f 1 | xargs。+1代表简洁明了的ans。
Bhushan

20

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

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

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

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

超级漂亮的解剖!
kyb


10

使用单个Awk:

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

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

要将其存储在变量中:

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

更加灵活的实现sed不需要将用户名设置为字段5:

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

也就是说,删除所有内容:,然后删除所有内容,直到last为止/sed可能比还要快awk,所以这种选择肯定更好。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.