简体   繁体   English

使用 awk 提取子字符串

[英]Use Awk to extract substring

Given a hostname in format of aaa0.bbb.ccc , I want to extract the first substring before .给定aaa0.bbb.ccc格式的主机名,我想提取之前的第一个子字符串. , that is, aaa0 in this case. ,即本例中的aaa0 I use following awk script to do so,我使用以下 awk 脚本来执行此操作,

echo aaa0.bbb.ccc | awk '{if (match($0, /\./)) {print substr($0, 0, RSTART - 1)}}'

While the script running on one machine A produces aaa0 , running on machine B produces only aaa , without 0 in the end.虽然在一台机器A上运行的脚本产生aaa0 ,但在机器B上运行只产生aaa ,最后没有0 Both machine runs Ubuntu/Linaro , but A runs newer version of awk(gawk with version 3.1.8 while B with older awk (mawk with version 1.2)两台机器都运行Ubuntu/Linaro ,但A运行较新版本的 awk(gawk 使用 3.1.8 版,而B使用旧版 awk(mawk 使用 1.2 版)

I am asking in general, how to write a compatible awk script that performs the same functionality ...我一般都在问,如何编写一个兼容的 awk 脚本来执行相同的功能......

You just want to set the field separator as .您只想将字段分隔符设置为. using the -F option and print the first field:使用-F选项并打印第一个字段:

$ echo aaa0.bbb.ccc | awk -F'.' '{print $1}'
aaa0

Same thing but using cut:同样的事情,但使用剪切:

$ echo aaa0.bbb.ccc | cut -d'.' -f1
aaa0

Or with sed :或使用sed

$ echo aaa0.bbb.ccc | sed 's/[.].*//'
aaa0

Even grep :甚至grep

$ echo aaa0.bbb.ccc | grep -o '^[^.]*'
aaa0

或者只是使用剪切:

echo aaa0.bbb.ccc | cut -d'.' -f1

I am asking in general, how to write a compatible awk script that performs the same functionality ...我一般都在问,如何编写一个兼容的 awk 脚本来执行相同的功能......

To solve the problem in your quesiton is easy.解决问题中的问题很容易。 (check others' answer). (检查其他人的答案)。

If you want to write an awk script, which portable to any awk implementations and versions (gawk/nawk/mawk...) it is really hard, even if with --posix (gawk)如果您想编写一个可移植到任何 awk 实现和版本(gawk/nawk/mawk...)的 awk 脚本,即使使用 --posix (gawk) 也非常困难

for example:例如:

  • some awk works on string in terms of characters, some with bytes一些 awk 以字符的形式处理字符串,一些以字节为单位
  • some supports \x escape, some not有些支持\x转义,有些不支持
  • FS interpreter works differently FS解释器的工作方式不同
  • keywords/reserved words abbreviation restriction关键字/保留词缩写限制
  • some operator restriction eg **一些运营商限制,例如**
  • even same awk impl.甚至相同的 awk impl。 (gawk for example), the version 4.0 and 3.x have difference too. (例如 gawk),4.0 和 3.x 版本也有区别。
  • the implementation of certain functions are also different.某些功能的实现也不同。 (your problem is one example, see below) (你的问题是一个例子,见下文)

well all the points above are just spoken in general.好吧,以上所有观点都只是笼统地说。 Back to your problem, you problem is only related to fundamental feature of awk.回到您的问题,您的问题仅与 awk 的基本功能有关。 awk '{print $x}' the line like that will work all awks. awk '{print $x}'这样的行适用于所有 awk。

There are two reasons why your awk line behaves differently on gawk and mawk:您的 awk 行在 gawk 和 mawk 上表现不同的原因有两个:

  • your used substr() function wrongly.您错误地使用了substr()函数。 this is the main cause.这是主要原因。 you have substr($0, 0, RSTART - 1) the 0 should be 1 , no matter which awk do you use.你有substr($0, 0, RSTART - 1) 0应该是1 ,无论你使用哪个 awk 。 awk array, string idx etc are 1-based. awk 数组、字符串 idx 等都是从 1 开始的。

  • gawk and mawk implemented substr() differently. gawk 和 mawk 以不同的方式实现substr()

You don't need awk for this...你不需要 awk 这...

echo aaa0.bbb.ccc | cut -d. -f1
cut -d. -f1 <<< aaa0.bbb.ccc

echo aaa0.bbb.ccc | { IFS=. read a _ ; echo $a ; }
{ IFS=. read a _ ; echo $a ; } <<< aaa0.bbb.ccc 

x=aaa0.bbb.ccc; echo ${x/.*/}

Heavier options:较重的选项:

sed:
echo aaa0.bbb.ccc | sed 's/\..*//'
sed 's/\..*//' <<< aaa0.bbb.ccc 
awk:
echo aaa0.bbb.ccc | awk -F. '{print $1}'
awk -F. '{print $1}' <<< aaa0.bbb.ccc 

You do not need any external command at all, just use Parameter Expansion in bash:您根本不需要任何外部命令,只需在 bash 中使用参数扩展:

hostname=aaa0.bbb.ccc
echo ${hostname%%.*}

if you don't want to change the input field separator, then it's possible to use split function:如果您不想更改输入字段分隔符,则可以使用拆分功能:

echo "some aaa0.bbb.ccc text" | awk '{split($2, a, "."); print a[1]}'

documentation : 文档

split(string, array [, fieldsep [, seps ] ])
    Divide string into pieces separated by fieldsep 
    and store the pieces in array and the separator 
    strings in the seps array.

awk is still the cleanest approach : awk仍然是最干净的方法:

 mawk NF=1 FS='[.]' <<< aaa0.bbb.ccc
aaa0

If there's stuff before or after :如果之前或之后有东西:

 mawk ++NF FS='[.].+$|^[^ ]* ' OFS= <<< 'some aaa0.bbb.ccc text' mawk '$!NF=$2' FS='[ .]' <<< 'some aaa0.bbb.ccc text'
aaa0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM