我遇到了一个极端的问题,我能想到的所有解决方案都很复杂。根据我的 UNIX/Linux 经验必须是一个简单的方法。
我想删除 .txt 文件中每个文件的前 31 个字节/foo/
。每个文件足够长。好吧,我确信有人会给我一个我无法想象的非常简单的解决方案。也许 awk ?
答案1
for file in /foo/*
do
if [ -f "$file" ]
then
dd if="$file" of="$file.truncated" bs=31 skip=1 && mv "$file.truncated" "$file"
fi
done
或者更快,感谢吉尔斯的建议:
for file in /foo/*
do
if [ -f $file ]
then
tail +32c $file > $file.truncated && mv $file.truncated $file
fi
done
注意:Posix tail 指定“-c +32”而不是“+32c”,但 Solaris 默认 tail 不喜欢它:
$ /usr/bin/tail -c +32 /tmp/foo > /tmp/foo1
tail: cannot open input
/usr/xpg4/bin/tail
两种语法都很好。
如果要保留原始文件权限,请替换
... && mv "$file.truncated" "$file"
经过
... && cat "$file.truncated" "$file" && rm "$file.truncated"
答案2
以下命令从中剪切前 31 个字节$file
(用作$file~
临时副本):
dd if="$file" of="$file~" bs=1 skip=31
mv "$file~" "$file"
您只需要列出find
下面的所有文件/foo/
并为每个找到的执行上面的两个文件$file
。
答案3
tail -c +32
输出其输入减去前 31 个字节。 (是的,参数相差一。)要就地编辑文件,使用海绵在循环中,或者如果您没有它并且不想打扰,请在 shell 中完成它的工作:
for x in /foo/*; do tail -c +32 "$x" | sponge "$x"; done
for x in /foo/*; do tail -c +32 "$x" >"$x.new" && mv "$x.new" "$x"; done
如果命令由于某种原因(例如电源故障)而中断,则可能很难弄清楚您在哪里中断。将新文件写入单独的目录会使事情变得更容易。
mkdir /foo.tmp
cd /foo
for x in *; do tail -c +42 -- "$x" >"/foo.tmp/$x" && rm -- "$x"; done
mv /foo.tmp/* /foo
rmdir /foo.tmp
如果文件非常大(例如,大到足以拥有两个副本,甚至一个副本都是问题),您可以使用该线程中提到的技术之一。
答案4
使用dd
块大小 1 的速度非常慢。可以使用较大的块大小,同时指定以字节为单位的跳过,如下所示:
dd iflag=skip_bytes if=infile.txt of=outfile.txt skip=31 bs=1M