【问题标题】:extract part of a string using bash/cut/split使用 bash/cut/split 提取字符串的一部分
【发布时间】:2013-10-29 05:07:15
【问题描述】:

我有一个这样的字符串:

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

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

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

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

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

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

【问题讨论】:

    标签: string bash


    【解决方案1】:

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

    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
    

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

    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
    

    【讨论】:

    • 甜蜜!它是在执行 shell 中完成的,因此比使用其他命令的 shell 更快。
    • @Fadi 您必须将通配符切换到冒号之前,并使用# 而不是%。如果您只想要最后一个冒号之后的部分,请使用${MYVAR##*:} 获取第一个冒号之后的部分,请使用${MYVAR#*:}
    • 朋友,你不知道我回到这个答案多少次了。谢谢!
    • 很好的答案!问题:如果我的模式是一个变量,我会像这样${RET##*$CHOP} 还是像这样${RET##*CHOP} (或其他方式)键入它?编辑:似乎是前者,${RET##*$CHOP}
    • fyi ${MYVAR::3} 表达式在 zsh 中不起作用。返回zsh: closing brace expected:3:5:3 工作正常。
    【解决方案2】:

    定义一个这样的函数:

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

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

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

    【讨论】:

    • 这个答案帮助我实现了我来这里的目的。没有公认的答案,我投票赞成简单。
    • 我必须在上述命令中做的唯一更正是删除':',就像echo $1 | cut -d -f 1 | xargs。 +1 简单整洁的答案。
    • 请描述您答案中的cut -d : -f 1 | xargs basename 部分,以便对其有类似用例的其他人有用
    【解决方案3】:

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

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

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

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

    【讨论】:

    • 超级好解剖!
    【解决方案4】:

    使用单个 awk:

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

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

    将其存储在变量中:

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

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

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

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

    【讨论】:

      【解决方案5】:

      使用单个 sed

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

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

        • 迟到总比没有好我的朋友。
        猜你喜欢
        • 2016-06-17
        • 1970-01-01
        • 2020-12-18
        • 1970-01-01
        • 1970-01-01
        • 2012-09-07
        • 1970-01-01
        相关资源
        最近更新 更多