欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

关于linux:如何使用’cut’查找最后一个字段 有大用

linux - 如何使用'cut'找到最后一个字段

不使用sed或awk,仅使用cut,如果字段数未知或每行更改,如何获取最后一个字段?

noobcoder asked 2019-03-15T12:47:58Z

11个解决方案

450 votes

你可以尝试这样的事情:

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

说明

maps.google.com的反向将是com

com使用点作为分隔符并选择第一个字段,即moc

最后,我们再次反转(感谢提醒,@ tom)获得com

zedfoxus answered 2019-03-15T12:48:42Z

95 votes

使用参数扩展。 这比任何类型的外部命令,包括cut(或grep)更有效。

data=foo,bar,baz,qux

last=${data##*,}

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

Charles Duffy answered 2019-03-15T12:49:16Z

65 votes

不可能只使用cut.这是使用grep的方法:

grep -o '[^,]*$'

替换其他分隔符的逗号。

tom answered 2019-03-15T12:49:58Z

14 votes

没有awk?...但是用awk这么简单:

echo 'maps.google.com' | awk -F. '{print $NF}'

AWK是一种更强大的工具,可放在口袋里。-F如果是字段分隔符NF是字段数(也代表最后一个的索引)

Amir Mehler answered 2019-03-15T12:50:36Z

12 votes

有多种方式。 你也可以使用它。

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

> here

显然,tr命令的空格输入应该用你需要的分隔符替换。

rjni answered 2019-03-15T12:51:21Z

5 votes

这是唯一可以使用除切割之外的解决方案:

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

使用这种解决方案,字段的数量确实是未知的,并且不时变化。 但是,由于行长度不得超过LINE_MAX字符或字段(包括换行符),因此任意数量的字段都不能成为此解决方案的真实条件。

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

A friend answered 2019-03-15T12:52:22Z

1 votes

以下实现了朋友的建议

#!/bin/bash

rcut(){

nu="$( echo $1 | cut -d"$DELIM" -f 2- )"

if [ "$nu" != "$1" ]

then

rcut "$nu"

else

echo "$nu"

fi

}

$ export DELIM=.

$ rcut a.b.c.d

d

user2166700 answered 2019-03-15T12:52:54Z

0 votes

如果您有一个名为filelist.txt的文件,它是一个列表路径,如下所示:C:/dir1/dir2/file1.hC:/dir1/dir2/dir3/file2.h

然后你可以这样做:rev filelist.txt | cut -d“/” - f1 |转

aperson1961 answered 2019-03-15T12:53:44Z

0 votes

我意识到如果我们只确保存在一个尾随分隔符,它就可以工作。 所以在我的情况下,我有逗号和空格分隔符。 我在最后加了一个空格;$ ans="a, b"

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

b

AnneTheAgile answered 2019-03-15T12:54:17Z

0 votes

如果您的输入字符串不包含正斜杠,那么您可以使用|和子shell:

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

这不使用|或awk,但它也不使用cut,所以我不太确定它是否有资格作为其措辞的问题的答案。

如果处理可以包含正斜杠的输入字符串,则这不起作用。 这种情况的解决方法是将正斜杠替换为您知道不属于有效输入字符串的其他字符。 例如,管道(|)字符也不允许在文件名中,因此这将起作用:

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

jstine answered 2019-03-15T12:55:05Z

-1 votes

你可以用bash shell编写一个小程序。

你可以参考我的bash shell [https://www.huuphan.com/2018/06/split-string-in-shell-and-get-last-field.html]

我希望这对你有所帮助!

Phan Văn Hữu answered 2019-03-15T12:55:54Z


来自  https://blog.csdn.net/weixin_36240219/article/details/116875869?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v31_ecpm-4-116875869-null-null.pc_agg_new_rank&utm_term=linux%E6%88%AA%E5%8F%96%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6&spm=1000.2123.3001.4430




How to find the last field using 'cut'

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


  • 你不能。为什么必须使用

    cut

  • 您是否爱上

    cut

    命令:)?为什么没有其他Linux命令?

  • 如果没有

    sed

    awk

    perl -pe s^.+\s+([^\s]+)$$1

  • @jaynesh如zfus正确猜中,是的,这是家庭作业,我们不能使用sed或awk。如果我有几行简单的文本,其中每一行都是一个网址,则有一个定界符。我需要从那些网址中提取最后一个字段,即com,net,nz。但是数量。 (定界符)始终随每个地址而变化,但始终是最后一个字段。我认为削减是显而易见的选择:

  • 如果将问题仅限于期望的答案(在本例中为

    cut

    ),则您将无法学习任何新知识。

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

  • 这也很愚蠢:仅

    cut

    不能执行此任务。您需要其他工具。因此,您不能使用

    sed

    awk

    ,但是可以使用

    grep

    rev

    ?调用内联

    python

    perl

    脚本怎么办?完全不使用

    cut

    怎么办?

  • @MestreLion很多时候,人们阅读问题以找到解决问题的方法。这从错误的前提开始,即

    cut

    支持它不支持的功能。但是我认为它很有用,因为它迫使读者考虑更易于遵循的代码。我想要一种快速,简单的使用

    cut

    的方法,而无需对

    awk

    grep

    sed

    等使用多种语法。非常优雅,而且我从未考虑过(即使在其他情况下笨拙)。我也喜欢从其他答案中阅读其他方法。

  • @EliranMalka谢谢。感谢您的反馈。我在尝试。

  • 这是一个现实生活中的问题:我想在源代码树中找到所有不同的文件扩展名,以更新.gitattributes文件。所以

    find | cut -d. -f

    是自然倾向

  • 顺便说一句,@ studog,如果在GNU平台上,

    find . -printf %f

    将仅自行发出文件名。




您可以尝试这样的事情:

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

说明

  • maps.google.com的反向为

    moc.elgoog.spam
  • cut

    使用点作为定界符并选择第一个字段,即

    moc
  • 最后,我们再次将其反转(感谢提醒@tom)以获得

    com


  • 这个"仅

    cut

    "如何?

  • 它不仅使用

    cut

    ,而且不使用

    sed

    awk

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

  • @zfus我明白了。之后可能要粘贴另一个

    rev

  • @zfus我认为您还需要另一个

    rev

    ,因为在类似

    echo www.google.com | rev | cut -d. -f 1 | rev

    的情况下。

  • rev

    非常理想!

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

  • 如果您没有

    rev

    ,请尝试

    perl -ple $_ = reverse




使用参数扩展。这比包括cut(或grep)的任何种类的外部命令要高效得多。

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

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


  • @ErwinWessels:因为bash真的很慢。使用bash运行管道,而不是批量处理数据。我的意思是,如果您在shell变量中已经有一行文本,或者您想执行

    while IFS= read -ra array_var; do :;done <(cmd)

    处理几行文本,那么这很好。但是对于大文件,rev | cut | rev可能更快! (当然awk会比那快。)

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

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

  • 到目前为止,这是在

    bash

    脚本中精简单个变量的最快,最简洁的方法(假设您已经在使用

    bash

    脚本)。无需调用任何外部。

  • 虽然这看起来确实很整洁,但我还是更喜欢double rev,它不是bash特有的。它学到了我一个新工具!请注意,我一直使用bash,但永远不会提醒那些古怪而野蛮的语法。

  • @Balmipour,...,但是

    rev

    特定于您使用的提供此功能的任何操作系统-尚未在所有UNIX系统上标准化。有关命令和实用程序的POSIX部分,请参见列出的章节-此处不存在。而且

    ${var##prefix_pattern}

    实际上不是bash特定的;它在POSIX sh标准中,请参阅第2.6.2节(链接)的结尾,因此与

    rev

    不同,它始终可在任何兼容的shell上使用。

  • @Balmipour,...如果您从事学习新工具的业务,则可以考虑学习具有良好运行时性能特征的工具的好处。 shell之所以以速度慢而闻名,其原因的一半是因为许多人习惯于编写效率低下的脚本,并在内部脚本会用时使用外部命令。 (另一半是我和Peter先前讨论的问题-解释器的性能-但是如果您在紧密的循环中扩展外部工具,那么比较起来,解释器的性能就不那么明显了)。

  • @Charles Duffy感谢您的精确度。我从不需要外壳脚本中的性能,但是就这一点以及它的POSIX标准(我不知道)的事实而言,您显然是正确的。猜猜选择在很大程度上取决于需求,但是我很乐意对此有所了解:)

  • 要求切|转速快一点是完全没有根据的。与字符串扩展相比,它非常慢。在我的系统上,字符串扩展的10000次重复花费0.398秒。 rev | cut | rev耗时1分钟6秒

  • @ Bruno9779,因此,它取决于实现细节。如果您为要反转的每个字符串增加一个新的管道,那将非常慢-正如您所注意到的。如果您通过发送10,000个字符串来重用单个管道,则它会比同等的本机bash更快-这大概就是PeterCordes所说的。就是说,单管道重用实际上很少是实际可行的,因此我同意您的观点,通常来说,参数扩展是正确的选择。

  • @ Bruno9779,...提供了一个仅使用一个管道即可非常快速地处理大量行的具体示例:在

    for ((i=0; i<10000; i++)); do echo"foo,bar,baz,$RANDOM"; done >file; time { rev devnull; }

    中,

    time

    覆盖的部分在我的本地系统上花费了0m0.026s挂钟时间。

  • 您可以概括一下以得出最后一个领域的结论吗? 

    rev|cut|rev

    答案很容易适应以获取任何字段...

  • @GiacomoAlzetta,

    n=2; IFS=, read -r -a fields; echo"${fields[${#fields[@]}-n]}"

    -在ideone.com/gMUu1x上查看它的运行情况






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

1
grep -o '[^,]*$'

用逗号分隔其他定界符。


  • 若要执行相反的操作,并找到除最后一个字段以外的所有内容,请执行以下操作:

    grep -o ^.*,
  • 这特别有用,因为在我的情况下

    rev

    添加了问题多字节unicode字符。

  • 我试图在MinGW上执行此操作,但是我的grep版本不支持-o,所以我使用了

    sed s^.*,

    ,该字符用空字符串替换直到最后一个逗号(包括最后一个逗号)的所有字符。




没有awk吗?
但是使用awk是如此简单:

1
echo 'maps.google.com' | awk -F. '{print $NF}'

AWK是一种功能更强大的工具,可以放在口袋里。
-F如果用于字段分隔符
NF是字段数(也代表最后一个的索引)


  • 这是通用的,并且每次都完全按预期运行。在这种情况下,使用

    cut

    实现OP的最终输出就像使用勺子"切"牛排(双关语:))。 

    awk

    是牛排刀。

  • 避免不必要地使用

    echo

    ,这可能会降低使用

    awk -F. {print $NF} <<< maps.google.com

    的长文件的脚本速度。




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

1
2
3
echo"Your string here"| tr ' ' '
'
 | tail -n1
> here

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


  • 谢谢!在busybox sh 1.0.0中起作用的东西:)

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

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




这是仅使用cut的唯一可能解决方案:

echo"s.t.r.i.n.g." | cut -d'.' -f2-
[repeat_following_part_forever_or_until_out_of_memory:] | cut -d'.' -f2-

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

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


  • 真好就拿最后一个。脱离" s.t.r.i.n.g."这可行。

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

  • 可以循环循环

    cut -f2-

    ,直到输出不再更改为止。






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

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

这不使用sedawk,但是也没有使用cut,因此我不确定它是否可以用措词回答问题。

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

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

以下实现朋友的建议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
rcut(){

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

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


  • 您需要在

    echo

    的参数两边加上双引号,以使其可靠且可靠地工作。见stackoverflow.com/questions/10067266/




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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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。
好吧,我想是回声。


  • 嗯,为什么不完全删除剪切并仅使用bash ... x] 

    while read -r line; do echo ${line*;}; done <input.file< wyn="" style="box-sizing: border-box;">会产生相同的结果。




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

那么您可以执行以下操作:
rev filelist.txt |切-d" /" -f1 |转速


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

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


  • 并且

    ans="a, b, c"

    产生

    b

    ,它不满足"字段数未知或每行更改"的要求。


来自  https://www.codenong.com/22727107/


普通分类: