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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19482123/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 02:07:47  来源:igfitidea点击:

extract part of a string using bash/cut/split

stringbash

提问by Craig Edmonds

I have a string like this:

我有一个这样的字符串:

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

I need to extract the username (joebloggs) from this string and store it in a variable.

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

The format of the string will always be the same with exception of joebloggsand domain.comso I am thinking the string can be split twice using cut?

字符串的格式将始终相同,除了等joebloggsdomain.com所以我认为字符串可以使用cut?

The first split would split by :and we would store the first part in a variable to pass to the second split function.

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

The second split would split by /and store the last word (joebloggs) into a variable

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

I know how to do this in php using arrays and splits but I am a bit lost in bash.

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

回答by beroe

To extract joebloggsfrom this string in bash using parameter expansion without any extra processes...

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

Doesn't depend on joebloggsbeing at a particular depth in the path.

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



Summary

概括

An overview of a few parameter expansion modes, for reference...

几种参数扩展方式的概述,供参考...

${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

So #means match from the beginning (think of a comment line) and %means from the end. One instance means shortest and two instances means longest.

所以#意味着从头开始匹配(想想注释行)和%从最后开始。一个实例表示最短,两个实例表示最长。

You can get substrings based on position using numbers:

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

${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)

You can also replace particular strings or patterns using:

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

${MYVAR/search/replace}

The patternis in the same format as file-name matching, so *(any characters) is common, often followed by a particular symbol like /or .

pattern是在相同的格式的文件名匹配,所以*(任何字符)是常见的,经常随后像特定符号/.

Examples:

例子:

Given a variable like

给定一个变量,如

MYVAR="users/joebloggs/domain.com" 

Remove the path leaving file name (all characters up to a slash):

删除留下文件名的路径(所有字符最多为斜杠):

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

Remove the file name, leaving the path (delete shortest match after last /):

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

echo ${MYVAR%/*}
users/joebloggs

Get just the file extension (remove all before last period):

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

echo ${MYVAR##*.}
com

NOTE:To do two operations, you can't combine them, but have to assign to an intermediate variable. So to get the file name without path or extension:

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

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

回答by Stefano Sanfilippo

Define a function like this:

定义一个这样的函数:

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

And pass the string as a parameter:

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

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

回答by David W.

What about sed? That will work in a single command:

sed呢?这将在单个命令中工作:

sed 's#.*/\([^:]*\).*##' <<<$string
  • The #are being used for regex dividers instead of /since the string has /in it.
  • .*/grabs the string up to the last backslash.
  • \( .. \)marks a capture group. This is \([^:]*\).
    • The [^:]says any character _except a colon, and the *means zero or more.
  • .*means the rest of the line.
  • \1means substitute what was found in the first (and only) capture group. This is the name.
  • #被用于正则表达式的分隔,而不是/因为字符串有/它。
  • .*/抓取字符串直到最后一个反斜杠。
  • \( .. \)标记捕获组。这是\([^:]*\)
    • [^:]说_except冒号任何字符,并*表示零以上。
  • .*表示该行的其余部分。
  • \1意味着替换在第一个(也是唯一一个)捕获组中找到的内容。这就是名字。

Here's the breakdown matching the string with the regular expression:

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

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

回答by Yann Moisan

Using a single sed

使用单个 sed

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

回答by janos

Using a single Awk:

使用单个 awk:

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

That is, using as field separator either /or :, the username is always in field 5.

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

To store it in a variable:

要将其存储在变量中:

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

A more flexible implementation with sedthat doesn't require username to be field 5:

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

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

That is, delete everything from :and beyond, and then delete everything up until the last /. sedis probably faster too than awk, so this alternative is definitely better.

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