不使用sedawk而不使用cut,当字段数未知或每行更改时,如何获取最后一个字段?

评论

您是否爱上cut命令:)?为什么没有其他Linux命令?

不使用sed或awk:perl -pe's /^.+ \ s +([^ \ s] +)$ / $ 1 /'。

如何在shell中拆分字符串并获取最后一个字段的可能重复项

@MestreLion很多时候,人们阅读问题以找到解决问题的方法。这从一个错误的前提开始,即割支持不支持的东西。但是我认为它很有用,因为它迫使读者考虑更容易理解的代码。我想要一种快速,简单的使用cut的方式,而无需对awk,grep,sed等使用多种语法。非常优雅,这是我从未考虑过的(即使在其他情况下笨拙)。我也喜欢从其他答案中阅读其他方法。

这是一个现实生活中的问题:我想在源代码树中找到所有不同的文件扩展名,以更新.gitattributes文件。因此找到|切-d。 -f 是自然倾斜度

#1 楼

您可以尝试执行以下操作:

echo 'maps.google.com' | rev | cut -d'.' -f 1 | rev


说明



rev会反转“ maps.google.com”成为moc.elgoog.spam


cut使用点(即'。')作为定界符,并选择第一个字段,即moc

最后,我们将其反转再次获得com



评论


它不仅使用cut,而且不使用sed或awk。

–Jayesh Bhoi
2014年3月29日在5:02



在过去的几个小时中,@ tom OP不仅问了更多问题。根据与OP的交互,我们知道awk / sed / etc。不允许在他的家庭作业中使用,但尚未提及rev。所以值得一试

–zedfoxus
2014年3月29日在5:03

@zfus我明白了。之后可能要再贴一个转速。

–tom
2014年3月29日5:04



双转非常理想!

–福特郭
15年3月31日在9:36

很棒,简单,完美,也感谢您的解释-没有足够的人来解释管道命令的长链中的每个步骤

– Pete
16年4月12日在11:32

#2 楼

使用参数扩展。这比包括cut(或grep)在内的任何类型的外部命令都效率更高。

data=foo,bar,baz,qux
last=${data##*,}


有关Bash中本机字符串操作的介绍,请参见BashFAQ#100。

评论


@ErwinWessels:因为bash真的很慢。使用bash运行管道,而不是批量处理数据。我的意思是,如果您在shell变量中已经有一行文本,或者如果您想在IFS = read -ra array_var;时执行此操作,那就太好了。做:;完成<(cmd)处理几行。但是对于大文件,rev | cut | rev可能更快! (当然,awk会比那更快。)

– Peter Cordes
2015年12月7日在6:30



@PeterCordes,对于大文件,awk肯定会更快,但是要克服恒定因素的启动成本,它需要花费大量的输入。 (还存在一些shell,例如ksh93,其性能接近awk,此答案中给出的语法仍然有效; bash异常缓慢,但它甚至与可用的唯一选项都不接近)。

–查尔斯·达菲(Charles Duffy)
2015年12月7日在6:33



谢谢@PeterCordes;像往常一样,我猜每个工具都有其用例。

–欧文·韦塞尔斯
2015年12月7日,11:50

到目前为止,这是在bash脚本中修剪单个变量的最快,最简洁的方法(假设您已经在使用bash脚本)。无需调用任何外部。

–肯·夏普
17年7月28日在4:34

@Balmipour,...,但是,rev特定于您使用的提供它的任何操作系统-尚未在所有UNIX系统上标准化。有关命令和实用程序的POSIX部分,请参见列出的章节-它不存在。 $ {var ## prefix_pattern}实际上不是bash特定的;它在POSIX sh标准中,请参阅2.6.2节(链接)的结尾,因此与rev不同,它始终可在任何兼容的shell上使用。

–查尔斯·达菲(Charles Duffy)
17-10-13在11:15



#3 楼

仅使用cut是不可能的。这是使用grep的方法:

grep -o '[^,]*$'


用逗号分隔其他定界符。

评论


相反,找到除最后一个字段以外的所有内容:grep -o'^。*,'

– Ariel
16-3-11在6:59



这特别有用,因为在我的情况下rev添加了一个问题多字节unicode字符。

– Brice
17/12/21在15:04



我试图在MinGW上执行此操作,但是我的grep版本不支持-o,所以我使用sed的s /^.*,///替换了直到最后一个逗号(包括最后一个逗号)的所有字符。

– TamaMcGlinn
18年4月4日在14:16



#4 楼

没有awk吗?...
但是使用awk是如此简单: > -F,如果用于字段分隔符
NF是字段数(也代表最后一个的索引)

评论


这是通用的,并且每次都完全按预期运行。在这种情况下,使用cut来实现OP的最终输出就像使用勺子“切割”牛排(双关语:))。 awk是牛排刀。

–山核桃420
18-10-11在1:04



避免不必要地使用echo,这可能会降低使用awk -F的长文件的脚本的速度。 '{print $ NF}'<<<'maps.google.com'。

– Anil_M
18-10-17在20:36

#5 楼

有多种方法。您也可以使用它。

echo "Your string here"| tr ' ' '\n' | tail -n1
> here


显然,tr命令的空白输入应替换为所需的定界符。

评论


这感觉像是对我来说最简单的答案,更少的管道和更清晰的含义

–joeButler
17年1月12日在14:14

这不适用于整个文件,这可能是OP的意思。

–阿米尔
17年4月26日在7:24

#6 楼

这是唯一不使用cut的唯一解决方案:


echo“ s.t.r.i.n.g.” |切-d'。 -f2-
[repeat_following_part_forever_or_until_out_of_memory:] |切-d'。 -f2-


使用此解决方案,字段的数量确实可以是未知的,并且会不时变化。但是,由于行长不得超过LINE_MAX个字符或字段(包括换行符),因此,绝对不能将任意数量的字段作为此解决方案的真实条件。

是的,这很愚蠢解决方案,但唯一符合我认为标准的解决方案。

评论


真好只要取最后一个'。脱离“ s.t.r.i.n.g.”这可行。

–马特
16年8月12日在22:08

当每个人都说某事是不可能的,然后有人听到一个可行的答案时,我会喜欢。即使确实很傻。

–Beejor
16年8月23日在3:13

可以在循环中迭代cut -f2-,直到输出不再更改为止。

–loa_in_
18 Jun 25'11:11



#7 楼

如果您的输入字符串不包含正斜杠,则可以使用basename和一个子外壳:

$ basename "$(echo 'maps.google.com' | tr '.' '/')"


这不使用sedawk,但它也不使用也可以使用cut,所以我不太确定它是否符合其措词的答案。

如果处理包含正斜杠的输入字符串,此方法将无法正常工作。解决该问题的方法是将正斜杠替换为您知道不是有效输入字符串的一部分的其他字符。例如,文件名中也不允许使用竖线(|)字符,因此可以使用:

$ basename "$(echo 'maps.google.com/some/url/things' | tr '/' '|' | tr '.' '/')" | tr '|' '/'


#8 楼

以下实现朋友的建议

#!/bin/bash
rcut(){

  nu="$( echo  | cut -d"$DELIM" -f 2-  )"
  if [ "$nu" != "" ]
  then
    rcut "$nu"
  else
    echo "$nu"
  fi
}

$ export DELIM=.
$ rcut a.b.c.d
d


评论


您需要在参数周围加上双引号以进行回显,以使其可靠且可靠地工作。参见stackoverflow.com/questions/10067266/…

–tripleee
17年12月30日在14:24

#9 楼

如果您有一个名为filelist.txt的文件,该文件是诸如以下内容的列表路径:
c:/dir1/dir2/file1.h
c:/dir1/dir2/dir3/file2.h

,那么您可以执行以下操作:
rev filelist.txt |切-d“ /” -f1 | rev

#10 楼

为这个老问题添加一个方法只是为了好玩:

$ cat input.file # file containing input that needs to be processed
a;b;c;d;e
1;2;3;4;5
no delimiter here
124;adsf;15454
foo;bar;is;null;info

$ cat tmp.sh # showing off the script to do the job
#!/bin/bash
delim=';'
while read -r line; do  
    while [[ "$line" =~ "$delim" ]]; do
        line=$(cut -d"$delim" -f 2- <<<"$line")
    done
    echo "$line"
done < input.file

$ ./tmp.sh # output of above script/processed input file
e
5
no delimiter here
15454
info


除了bash之外,仅使用cut。
回声,我想。

评论


恩,为什么不完全删除cut并只使用bash ... x]读取-r行;做回声$ {line / *;};完成
– Kaffe Myers
19年5月27日,9:50

#11 楼

我意识到,只要确保存在尾随定界符,它就会起作用。因此,在我的情况下,我有逗号和空格分隔符。我在最后添加一个空格;

$ ans="a, b"
$ ans+=" "; echo ${ans} | tr ',' ' ' | tr -s ' ' | cut -d' ' -f2
b


评论


并且ans =“ a,b,c”产生b,它不满足“字段数未知或每行更改”的要求。

– jww
19 Mar 15 '19在8:17