没有使用sed
或awk
,仅cut
,当字段数未知或每行都在变化时,如何获取最后一个字段?
cut
命令吗 :)?为什么没有其他 Linux 命令?
sed
或 awk
:perl -pe 's/^.+\s+([^\s]+)$/$1/'
。
cut
支持它不支持的东西。但我认为它很有用,因为它迫使读者考虑更容易理解的代码。我想要一种快速、简单的方式来使用 cut
,而无需对 awk
、grep
、sed
等使用多种语法。rev
的事情成功了;非常优雅,而且我从未考虑过(即使在其他情况下很笨重)。我也喜欢从其他答案中阅读其他方法。
find | cut -d. -f<last>
是自然倾向
你可以尝试这样的事情:
echo 'maps.google.com' | rev | cut -d'.' -f 1 | rev
解释
rev 将“maps.google.com”反转为 moc.elgoog.spam
cut 使用点(即'.')作为分隔符,并选择第一个字段,即 moc
最后,我们再次反转它以获得 com
使用参数扩展。这比任何类型的外部命令(包括 cut
(或 grep
))都高效得多。
data=foo,bar,baz,qux
last=${data##*,}
有关 bash 中本机字符串操作的介绍,请参阅 BashFAQ #100。
while IFS= read -ra array_var; do :;done <(cmd)
来处理几行,这很好。但是对于大文件,rev|cut|rev 可能更快! (当然 awk 会比这更快。)
bash
脚本中缩减单个变量的最快、最简洁的方法(假设您已经在使用 bash
脚本)。无需调用任何外部的东西。
rev
特定于您使用的任何提供它的操作系统——它不是在所有 UNIX 系统中标准化的。请参阅 chapter listing for the POSIX section on commands and utilities - 它不存在。而 ${var##prefix_pattern}
实际上 不是 特定于 bash 的;它在 POSIX sh standard 中,请参阅第 2.6.2 节的末尾(链接),因此与 rev
不同,它始终在任何兼容的 shell 上可用。
仅使用 cut
是不可能的。这是使用 grep
的一种方式:
grep -o '[^,]*$'
替换其他分隔符的逗号。
解释:
-o (--only-matching) 仅输出与模式匹配的输入部分(如果包含匹配项,则默认打印整行)。
[^,] 是匹配除逗号以外的任何字符的字符类。
* 匹配前面的模式零次或多次,因此 [^,]* 匹配零个或多个非逗号字符。
$ 匹配字符串的结尾。
综上所述,该模式匹配字符串末尾的零个或多个非逗号字符。
当有多个可能的匹配时,grep 会选择最早开始的那个。所以整个最后一个字段将被匹配。
完整示例:
如果我们有一个名为 data.csv 的文件,其中包含
one,two,three
foo,bar
然后 grep -o '[^,]*$' < data.csv
将输出
three
bar
grep -o '^.*,'
rev
在我的例子中添加了一个问题多字节 unicode 字符。
sed 's/^.*,//'
将所有字符替换为空字符串(包括最后一个逗号)。
没有 awk ?...但是使用 awk 就这么简单:
echo 'maps.google.com' | awk -F. '{print $NF}'
AWK 是一种更强大的工具,可以放在你的口袋里。 -F 如果对于字段分隔符 NF 是字段数(也代表最后一个的索引)
cut
来实现 OP 的最终输出就像使用勺子“切”牛排(双关语:))。 awk
是牛排刀。
echo
,这可能会减慢使用 awk -F. '{print $NF}' <<< 'maps.google.com'
的长文件的脚本。
有多种方法。你也可以用这个。
echo "Your string here"| tr ' ' '\n' | tail -n1
> here
显然,tr 命令的空格输入应该替换为您需要的分隔符。
这是只使用 cut 的唯一解决方案:
回声“字符串” |切-d'。 -f2- [repeat_following_part_forever_or_until_out_of_memory:] |切-d'。 -f2-
使用这个解决方案,字段的数量确实是未知的,并且会不时变化。但是,由于行长度不得超过 LINE_MAX 个字符或字段,包括换行符,因此任意数量的字段永远不会成为此解决方案的真实条件。
是的,一个非常愚蠢的解决方案,但唯一符合我认为的标准的解决方案。
cut -f2-
,直到输出不再改变。
cut -f2-
直到它不再更改。否则你必须缓冲整个文件。
如果您的输入字符串不包含正斜杠,那么您可以使用 basename
和一个子shell:
$ basename "$(echo 'maps.google.com' | tr '.' '/')"
这不使用 sed
或 awk
,但它也不使用 cut
,所以我不太确定它是否有资格作为其措辞的问题的答案。
如果处理可以包含正斜杠的输入字符串,这将无法正常工作。这种情况的解决方法是将正斜杠替换为您知道不是有效输入字符串的一部分的其他字符。例如,管道 (|
) 字符也不允许出现在文件名中,因此可以这样做:
$ basename "$(echo 'maps.google.com/some/url/things' | tr '/' '|' | tr '.' '/')" | tr '|' '/'
touch \|
。
|
的虚假声明,我将从反对票改为赞成票。但是几乎所有的 tr
都支持 \0
或其他表达 nul 字节的方式,而且文件名中绝对不允许这样做,因此您可以将其用作占位符。此外,tr ab bc
只是毫无问题地交换所有 a
和 b
,因此您可以完全避免必须找到一个不允许的字符。只需通过 tr './' './'
一次以在 basename
之前交换,然后再次在之后交换回来。
tr '/.' './'
管道一次在基本名称之前交换,然后再在之后交换”。
#!/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/…
使用 perl 的替代方法是:
perl -pe 's/(.*) (.*)$/$2/' file
无论 file
的分隔符是什么,您都可以在其中更改 \t
如果您有一个名为 filelist.txt 的文件,它是一个列表路径,如下所示:c:/dir1/dir2/file1.hc:/dir1/dir2/dir3/file2.h
那么你可以这样做: rev filelist.txt |剪切 -d"/" -f1 |转
为这个老问题添加一种方法只是为了好玩:
$ 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。嗯,还有回声,我猜。
while read -r line; do echo ${line/*;}; done <input.file
会产生相同的结果。
我意识到如果我们只是确保存在尾随分隔符,它就可以工作。所以就我而言,我有逗号和空格分隔符。我在末尾添加了一个空格;
$ ans="a, b"
$ ans+=" "; echo ${ans} | tr ',' ' ' | tr -s ' ' | cut -d' ' -f2
b
ans="a, b, c"
产生b
,不符合“字段数未知或逐行变化”的要求。
cut
,而且没有sed
或awk
。那么 OP 怎么想?rev
。rev
伟大的理想!