我有这个变量:
A="Some variable has value abc.123"
我需要提取这个值,即abc.123
。在bash中是否可能?
最简单的方法是:
echo "$A" | awk '{print $NF}'
编辑:这是它的工作原理的解释...
awk
将输入拆分为不同的字段,默认使用空格作为分隔符。将 NF
的位置硬编码为 5
可以打印输入中的第五个字段:
echo "$A" | awk '{print $5}'
NF
是内置的 awk
变量,它给出当前记录中字段的总数。以下语句返回数字5,因为字符串 "Some variable has value abc.123"
中有5个字段:
NF
是一个内置的awk
变量,用于确定当前记录中的字段总数。下面的示例返回数字5,因为字符串"Some variable has value abc.123"
中有5个字段:
echo "$A" | awk '{print NF}'
将$
与NF
组合在一起,可以输出字符串中的最后一个域,无论该字符串包含多少个域。
是的;这样做:
A="Some variable has value abc.123"
echo "${A##* }"
将打印出这个:
abc.123
(${parameter##word}
表示法在§3.5.3 "Bash 参考手册"的 "Shell 参数扩展"一节中有解释。)
使用参数扩展的一些示例
A="Some variable has value abc.123"
echo "${A##* }"
abc.123
在空格" "上的最长匹配
echo "${A% *}"
Some variable has value
点号上的最长匹配
echo "${A%.*}"
Some variable has value abc
" "空格的最短匹配
echo "${A%% *}"
some
阅读更多 Shell参数扩展
这份文档有点难以阅读,所以我用更简单的方式进行了总结。
请注意,根据您使用的是#
还是%
,'*
'需要与'
'交换位置。(*
只是一个通配符,所以在阅读时可能需要摘下您的"正则表达式帽子"。)
${A% *}
- 删除最短的尾部 *
(去除最后一个单词)${A%% *}
- 删除最长的尾部 *
(去除最后几个单词)${A#* }
- 删除最短的前导*
(去除第一个单词)${A##* }
- 删除最长的前导*
(去除前几个单词)当然,在这里,一个"单词"可以包含任何不是字面上的空格的字符。
你可能经常使用这个语法来修剪文件名中的其他字符:${A##*/}
从路径的开头删除所有包含的文件夹(如果有的话),例如:
/usr/bin/git
-> git
/usr/bin/
-> 空字符串
/usr/bin
-> bin
${A%/*}
从路径的末尾删除最后一个文件夹/文件/斜杠(如果有的话):
/usr/bin/git
-> /usr/bin
/usr/bin/
-> /usr/bin
/usr/bin
-> /usr/
${A%.*}
删除最后一个扩展名(如果有的话,但要注意像/my.path/noext
这样的情况):
archive.tar.gz
-> archive.tar
/my.path/noext
-> /my
(!)
%.ext
而不是%.*
。my.path/noext
这样的路径上?例如,在/etc/*.d/
上会发生这种情况。 - undefined.conf
,你可以使用${A%.conf}
。如果字符串不是以.conf
结尾,它会保持不变。 - undefined如何知道值从哪里开始?如果它总是第五和第六个单词,你可以使用例如:
B=$(echo "$A" | cut -d ' ' -f 5-)
这里使用 cut
命令来截取行的一部分,使用简单的空格作为单词分隔符。
A="Some variable has value abc.123"
echo "$A" | rev | cut -d ' ' -f 1 | rev
# abc.123
更多方法:
(在终端中运行以下每个命令以测试实时效果。)
对于以下所有答案,请首先在终端中输入以下内容:
A="Some variable has value abc.123"
数组示例(下面的第3个示例)是非常有用的模式,根据您想要做什么,有时是最佳选择。
awk
,如主答案所示(链接)echo "$A" | awk '{print $NF}'
grep
命令:echo "$A" | grep -o '[^ ]*$'
-o
用于保留字符串中与模式匹配的部分。[^ ]
表示“不匹配空格”,即“不是空格字符”。*
的意思是:“匹配前面匹配模式(即 [^ ]
)的 0 或多个实例”,而 $
的意思是“匹配行尾”。因此,这将匹配最后一个空格之后到行尾的最后一个单词;在本例中为 abc.123
。使用默认的 IFS
(内部字段分隔符)字符(即空格),将 A
转换为数组:
A
variable contains certain special shell characters, so Option 2 below is recommended instead!):
# Capture space-separated words as separate elements in array A_array
A_array=($A)
read
command, as I explain in my answer here, and as is recommended by the bash shellcheck
static code analyzer tool for shell scripts, in ShellCheck rule SC2206, here.
# Capture space-separated words as separate elements in array A_array, using
# a "herestring".
# See my answer here: https://dev59.com/9mAf5IYBdhLWcg3wdCd1#71575442
IFS=" " read -r -d '' -a A_array <<< "$A"
# Print only the last element via bash array right-hand-side indexing syntax
echo "${A_array[-1]}" # last element only
输出:
abc.123
更进一步:
这种模式的另一个有用之处在于它还允许您轻松地执行相反操作!例如,可以像这样获取除最后一个单词以外的所有单词:
array_len="${#A_array[@]}"
array_len_minus_one=$((array_len - 1))
echo "${A_array[@]:0:$array_len_minus_one}"
输出:
Some variable has value
以上的${array[@]:start:length}
数组切片语法,详见我的答案:Unix & Linux: Bash: slice of positional parameters。关于bash的“算术扩展”语法的更多信息,请参见以下链接:
A_array=($A)
更改为IFS=" " read -r -d '' -a A_array <<< "$A"
来修复了我的答案,这是一种推荐的“选项2”,用于将多个单词的字符串拆分成数组。 - Gabriel Staples你可以使用Bash正则表达式:
A="Some variable has value abc.123"
[[ $A =~ [[:blank:]]([^[:blank:]]+)$ ]] && echo "${BASH_REMATCH[1]}" || echo "no match"
输出:
abc.123
这适用于当前语言环境中的任何[:blank:]
分隔符(通常为[ \t]
)。 如果您想更具体化:
A="Some variable has value abc.123"
pat='[ ]([^ ]+)$'
[[ $A =~ $pat ]] && echo "${BASH_REMATCH[1]}" || echo "no match"
echo "Some variable has value abc.123"| perl -nE'say $1 if /(\S+)$/'
我一直在关注类似的问题,寻找在破折号处拆分结果字符串的最佳策略。我的主要字符串是由空格或换行符分隔的窗口ID。我喜欢其中一些更聪明的答案,但最终这个平庸的解决方案似乎更高效,这让我感到惊讶,因为我在使用Python循环的经验中没有这样的表现:
A="Some variable has value abc.123"
for e in $A; do :; done; echo $e
for e in $(echo -e $A); do :; done; echo $e
awk -F "x"
来使用不同于空格的分隔符,但同样,这也可以通过shell内置命令轻松完成。 - tripleee${A##* }
,例如extract=${A##* }
或echo ${A##* }
。编辑:正如@mwfeamley的答案所说。 - jthill