修剪一行的最后3个字符而不使用sed或perl等
我有一个shell脚本输出这样的数据:
1234567890 * 1234567891 *
我需要删除只是最后三个字符“*”。 我知道我可以通过
(whatever) | sed 's/\(.*\).../\1/'
但我不想使用sed来达到速度的目的。 它将始终是最后3个字符。
任何快速清理输出的方法?
假设所有的数据都像你的例子那样格式化,使用' cut '来获得第一列。
cat $file | cut -d ' ' -f 1
或得到前10个字符。
cat $file | cut -c 1-10
这是一个老式的unix技巧,用于删除不使用sed或awk的行中的最后3个字符。
> echo 987654321 | rev | cut -c 4- | rev 987654
与之前使用“剪切”的示例不同,这不需要知道行长。
我可以向你保证, bash
本身不会比sed
更快。 在bash
启动外部进程通常是一个糟糕的主意,但只有当你做了很多事情。
所以,如果你为每一行input启动一个sed
进程,我会担心的。 但你不是。 你只需要启动一个 sed
来完成所有的工作。
你可能会发现下面的sed
会比你的版本快一点:
(whatever) | sed 's/...$//'
所有这些都是删除每行上的最后三个字符,而不是用一个较短的版本replace整行。 现在也许更现代的引擎可以优化你的命令,但为什么要冒这个风险。
说实话,我能想到的唯一方法就是更快地手工制作自己的基于C的filter程序。 唯一的原因可能比sed
更快,因为你可以利用你对处理需求的额外知识( sed
必须允许广义游戏,所以可能会因此而变慢)。
不要忘记优化的口头禅: “措施,不要猜测!”
如果你真的想在bash
一次做这一行(我仍然认为这是一个坏主意),你可以使用:
pax> line=123456789abc pax> line2=${line%%???} pax> echo ${line2} 123456789 pax> _
你也可能想调查你是否真的需要提高速度。 如果你将这些行加工成一个大块,你会发现sed
速度很快。 input以下内容:
#!/usr/bin/bash echo This is a pretty chunky line with three bad characters at the end.XXX >qq1 for i in 4 16 64 256 1024 4096 16384 65536 ; do cat qq1 qq1 >qq2 cat qq2 qq2 >qq1 done head -20000l qq1 >qq2 wc -l qq2 date time sed 's/...$//' qq2 >qq1 date head -3l qq1
并运行它。 这里是我的(不是很快)R40笔记本电脑的输出:
pax> ./chk.sh 20000 qq2 Sat Jul 24 13:09:15 WAST 2010 real 0m0.851s user 0m0.781s sys 0m0.050s Sat Jul 24 13:09:16 WAST 2010 This is a pretty chunky line with three bad characters at the end. This is a pretty chunky line with three bad characters at the end. This is a pretty chunky line with three bad characters at the end.
这是一秒钟内的2万行,对于每小时只能完成的事情来说是相当不错的。
$ x="can_haz" $ echo "${x%???}" can_
awk
和sed
都很快,但是如果你认为它很重要,可以使用下面的一种方法:
如果您要删除的字符总是在string的末尾
echo '1234567890 *' | tr -d ' *'
如果他们可以出现在string的任何地方,你只想在最后删除
echo '1234567890 *' | rev | cut -c 4- | rev
所有命令的手册页将解释发生了什么事情。
不过,我认为你应该使用sed
。
注意:这个答案有点意思是一个笑话,但它确实工作…
#!/bin/bash outfile="/tmp/$RANDOM" cfile="$outfile.c" echo '#include <stdio.h> int main(void){int e=1;char c;while((c=getc(stdin))!=-1){if(c==10)e=1;if(c==32)e=0;if(e)putc(c,stdout);}}' >> "$cfile" gcc -o "$outfile" "$cfile" rm "$cfile" cat somedata.txt | "$outfile" rm "$outfile"
你可以用不同的命令replacecat somedata.txt
。
你可以试试
(whatever) | while read line; do echo $line | head --bytes -3; done;
因为没有正则expression式或者分隔符匹配,所以head
本身应该比sed
或者更快,但是为每一行分别调用可能会超过这个。
如果脚本始终输出10个字符的行,然后是3个额外的(换句话说,您只需要前10个字符),则可以使用
script | cut -c 1-10
如果输出不确定数量的非空格字符,然后input一个空格,然后输出另外两个字符(换句话说,您只需要第一个字段),则可以使用
script | cut -d ' ' -f 1
……就像之前的majhool评论。 根据你的平台,你也可能有colrm,如果这些行是固定长度的话,它也可以工作:
script | colrm 11
另一个答案依赖于倒数第三个字符是一个空格。 这将与(几乎)在该位置的任何字符,并做到“没有使用sed,或perl等”:
while read -r line do echo ${line:0:${#line}-3} done
如果您的线路长度固定,则将echo
改为:
echo ${line:0:9}
要么
printf "%.10s\n" "$line"
但是其中的每一个肯定比sed
慢得多。
你可以使用awk来打印第一个'field',如果没有空格(或者如果有的话,改变分隔符)。
我把上面的字段放到一个文件中,然后做到这一点
awk '{ print $1 }' < test.txt 1234567890 1234567891
我不知道这是否更好。
你是什么意思不想使用sed / awk来达到速度的目的? sed / awk比读取循环处理文件时的shell速度更快。
$ sed 's/[ \t]*\*$//' file 1234567890 1234567891 $ sed 's/..\*$//' file 1234567890 1234567891
与bashshell
while read -rab do echo $a done <file
不需要剪切或魔术,在bash中你可以像这样剪切一个string:
ORGSTRING="123456" CUTSTRING=${ORGSTRING:0:-3} echo "The original string: $ORGSTRING" echo "The new, shorter and faster string: $CUTSTRING"