删除文件的前n个字节


32

我遇到了一个极端的问题,我能想到的所有解决方案都很复杂。根据我的UNIX / Linux经验,必须有一种简单的方法。

我想删除中每个文件的前31个字节/foo/。每个文件足够长。好吧,我敢肯定有人会为我提供一个我无法想象的超简单解决方案。也许awk?


2
任何awk / sed / ed解决方案都将面向行,因此,如果您不知道第一行至少包含31个字符,则会出现复杂情况。
格伦·杰克曼

Answers:


28
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尾部指定“ -c +32”而不是“ + 32c”,但是Solaris默认尾部不喜欢它:

   $ /usr/bin/tail -c +32 /tmp/foo > /tmp/foo1
    tail: cannot open input

/usr/xpg4/bin/tail 两种语法都很好。


1
dd此处建议过度矫kill,tail更恰当(更简单,更容易出现错字错误,stderr上没有虚假消息)。
吉尔(Gilles)'所以

你是对的。在处理可能的二进制文件时,我通常避免使用旨在处理文本文件的命令,但“ tail + 32c”将在此处工作。
jlliagre

1
@jlliagre:您已经写过cut (那不是尾巴吗?... asis,它对我不起作用...
Peter.O 2011年

当然是尾巴。抱歉,不匹配。
jlliagre 2011年

@jlliagre:在Solaris上,您应该/usr/xpg4/bin领先/usr/binPATH,否则您将陷于1990年代初期。许多unice(例如GNU,BusyBox)不再支持历史+32c语法,而是将其表示为一个名为的文件+32c(如POSIX要求)。
吉尔(Gilles)'所以

12

以下命令从$file$file~用作临时副本)剪切前31个字节:

dd if="$file" of="$file~" bs=1 skip=31
mv "$file~" "$file"

您只需要列出下面的find文件或所有文件,/foo/并对$file发现的每个文件执行上面的两个文件。


1
交换bs和跳过值将提高性能。
jlliagre 2011年

10

tail -c +32输出其输入减去前31个字节。(是的,自变量不存在。)要在适当位置编辑文件,请在循环中使用海绵,或者如果您没有文件又不想打扰,请在外壳中执行其工作:

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

如果文件确实很大(例如,足够大以至于即使只有一个副本都有两个副本都是一个问题),则可以使用此线程中提到的一种技术


2

您可以在Ex模式下使用Vim:

for each in /foo/*
do
  ex -sc '%!tail -c+32' -cx "$each"
done
  1. % 选择所有行

  2. ! 运行命令

  3. x 保存并关闭

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.