我需要使用bash脚本从一个巨大的文本文件中反复删除第一行。
现在我正在使用sed - I -e "1d" $FILE -但它需要大约一分钟的时间来删除。
有没有更有效的方法来实现这个目标?
我需要使用bash脚本从一个巨大的文本文件中反复删除第一行。
现在我正在使用sed - I -e "1d" $FILE -但它需要大约一分钟的时间来删除。
有没有更有效的方法来实现这个目标?
不,这是你能得到的最高效率。您可以编写一个C程序,它可以更快地完成这项工作(更少的启动时间和处理参数),但随着文件变大,它可能会趋向于与sed相同的速度(如果需要一分钟,我就假定它们很大)。
但是你的问题和其他问题一样,都是以解决方案为前提的。如果你能详细地告诉我们你正在尝试做什么,而不是如何做,我们可能会提出一个更好的选择。
例如,如果这是一个由其他程序B处理的文件a,一种解决方案是不去掉第一行,而是修改程序B以不同的方式处理它。
假设您的所有程序都附加到这个文件A,程序B当前在删除它之前读取并处理第一行。
您可以重新设计程序B,这样它就不会试图删除第一行,而是在文件a中维护一个持久的(可能是基于文件的)偏移量,以便下次运行时,它可以查找该偏移量,处理那里的行,并更新偏移量。
然后,在一个安静的时间(午夜?),它可以对文件a进行特殊处理,删除当前处理的所有行,并将偏移量设置为0。
对于程序来说,打开并查找文件肯定比打开并重写要快。当然,这个讨论假设您可以控制程序B。我不知道是不是这样,但如果你提供进一步的信息,也许还有其他可能的解决方案。
因为听起来我不能加快删除,我认为一个好的方法可能是像这样批量处理文件:
While file1 not empty
file2 = head -n1000 file1
process file2
sed -i -e "1000d" file1
end
这样做的缺点是,如果程序在中间被杀死(或者如果其中有一些糟糕的sql -导致“进程”部分死亡或锁定),将会有行被跳过,或者被处理两次。
(file1包含SQL代码行)
正如帕克斯所说,你可能不会比这更快。原因是几乎没有文件系统支持从文件的开头截断,所以这将是一个O(n)操作,其中n是文件的大小。不过,您可以更快地做的是用相同数量的字节(可能是空格或注释)覆盖第一行,这可能对您有用,具体取决于您正在尝试做什么(顺便说一下,这是什么?)
在N-1行上使用tail并将其定向到一个文件中,然后删除旧文件,并将新文件重命名为旧名称,这样做可以吗?
如果我以编程方式执行此操作,我将读取文件,并在读取每一行后记住文件偏移量,因此我可以查找回该位置以读取文件中少一行的文件。
试着尾巴:
tail -n +2 "$FILE"
-n x:只打印最后x行。Tail - n5表示输入的最后5行。+号有点颠倒了参数,使tail打印除第一个x-1行以外的任何内容。尾部-n +1输出整个文件,尾部-n +2输出除第一行以外的所有内容,等等。
GNU tail比sed快得多。tail在BSD上也可用,并且-n +2标志在这两个工具中是一致的。查看FreeBSD或OS X手册页了解更多信息。
不过,BSD版本可能比sed慢得多。我不知道他们是怎么做到的;Tail应该只是逐行读取文件,而sed则执行相当复杂的操作,包括解释脚本、应用正则表达式等。
注意:您可能会忍不住使用
# THIS WILL GIVE YOU AN EMPTY FILE!
tail -n +2 "$FILE" > "$FILE"
但这将给您一个空文件。原因是重定向(>)发生在shell调用tail之前:
Shell截断文件$ file Shell为tail创建一个新进程 Shell将尾部进程的stdout重定向到$FILE tail从现在空的$FILE中读取
如果你想删除文件中的第一行,你应该使用:
tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
&&将确保当出现问题时文件不会被覆盖。
如果您要做的是在失败后恢复,那么您可以构建一个包含迄今为止所做的工作的文件。
if [[ -f $tmpf ]] ; then
rm -f $tmpf
fi
cat $srcf |
while read line ; do
# process line
echo "$line" >> $tmpf
done
你可以编辑文件:使用perl的-i标志,像这样:
perl -ni -e 'print unless $. == 1' filename.txt
这将使第一行消失。Perl将需要读取和复制整个文件,但是它会将输出保存在原始文件的名称下。
您可以使用-i来更新文件,而不使用'>'操作符。下面的命令将从文件中删除第一行并将其保存到文件中(在幕后使用临时文件)。
sed -i '1d' filename
如果你想修改文件,你总是可以使用原始的ed,而不是它的流继承者sed:
ed "$FILE" <<<$'1d\nwq\n'
ed命令是最初的UNIX文本编辑器,当时还没有全屏终端,更不用说图形工作站了。ex编辑器,就是在vi中键入冒号提示符时所使用的编辑器,是ed的扩展版本,因此许多相同的命令都可以工作。虽然ed是用于交互的,但它也可以通过发送一串命令以批处理模式使用,这就是这个解决方案所做的。
序列<<<$'1d\nwq\n'利用了现代shell对here-strings(<<<)和ANSI引号($'…')的支持,将输入提供给由两行组成的ed命令:1d删除第一行,然后wq将文件写回磁盘,然后退出编辑会话。
你可以很容易地做到这一点:
cat filename | sed 1d > filename_without_first_line
在命令行上;或者要永久删除文件的第一行,使用sed的in-place模式,并带-i标志:
sed -i 1d <filename>
这一行代码可以做到:
echo "$(tail -n +2 "$FILE")" > "$FILE"
它可以工作,因为tail在echo之前执行,然后文件被解锁,因此不需要临时文件。
基于其他3个答案,我想出了这个语法,在我的Mac OSx bash shell中完美地工作:
Line =$(head -n1 list.txt && echo "$(tail -n +2 list.txt)"> list.txt)
测试用例:
~> printf "Line #%2d\n" {1..3} > list.txt
~> cat list.txt
Line # 1
Line # 2
Line # 3
~> line=$(head -n1 list.txt && echo "$(tail -n +2 list.txt)" > list.txt)
~> echo $line
Line # 1
~> cat list.txt
Line # 2
Line # 3
可以使用sed命令按行号删除任意行
# create multi line txt file
echo """1. first
2. second
3. third""" > file.txt
删除行并打印到标准输出
$ sed '1d' file.txt
2. second
3. third
$ sed '2d' file.txt
1. first
3. third
$ sed '3d' file.txt
1. first
2. second
# delete multi lines
$ sed '1,2d' file.txt
3. third
# delete the last line
sed '$d' file.txt
1. first
2. second
使用-i选项就地编辑文件
$ cat file.txt
1. first
2. second
3. third
$ sed -i '1d' file.txt
$cat file.txt
2. second
3. third