我可以使`cut`到位更改文件吗?


Answers:


14

你不能 使用ed或GNU sed或perl,或在后台进行操作,即为内容创建一个新文件。

ed,便携式:

ed foo <<EOF
1,$s/^\([^,]*\),\([^,]*\),\([^,]*\).*/\1,\3/
w
q
EOF

GNU sed

sed -i -e 's/^\([^,]*\),\([^,]*\),\([^,]*\).*/\1,\3/' foo

Perl:

perl -i -l -F, -pae 'print @F[1,3]' foo

cut,创建一个新文件(建议,因为如果脚本被中断,则可以再次运行它):

cut -d , -f 1,3 <foo >foo.new &&
mv -f foo.new foo

cut,就地替换文件(保留的所有权和权限foo,但需要保护以防中断):

cp -f foo foo.old &&
cut -d , -f 1,3 <foo.old >foo &&
rm foo.old

我建议使用cut基于-的方法之一。这样,您就不必依赖任何非标准工具,可以使用最佳工具来完成工作,并且可以控制中断时的行为。


.old就地更改的方法更好,echo "$(cut -d , -f 1,3 <foo)" > foo
GypsyCosmonaut

1
@GypsyCosmonaut不,这不是“更好”。比较脆弱。唯一的好处是它的键入时间较短。该方法的主要问题是,如果在处理输入文件或写入输出时发生错误,则数据将丢失。它也不适用于二进制数据:输出将在第一个空字节处被截断。即使使用文本文件,它也会从文件末尾删除空行。对于大文件,可能会失败,因为数据必须作为字符串存储在外壳的内存中(请记住,如果发生这种情况,数据将丢失)。
吉尔斯(Gills)'所以

谢谢,我不知道null字节可能存在问题
GypsyCosmonaut

我认为这更简单:cut -d , -f 1,3 foo > foo.new rm foo mv foo.new foo
LoMaPh

@LoMaPh实际上,我不知道为什么要重命名旧文件:重命名新文件没有任何优势。这也更简单,因为您不需要步骤rm foo。而且您不应该调用rm foo,因为mv foo.new foo它是原子的:它将删除旧版本,同时将新版本放置到位。
吉尔斯(Gilles)'所以

23

ubuntu 的moreutils软件包(还有debian)有一个名为的程序sponge,该程序也可以解决您的问题。

从男人海绵:

海绵读取标准输入并将其写到指定文件中。与shell重定向不同,海绵在打开输出文件之前先吸收所有输入。这样可以限制读取和写入同一文件的管道。

这会让您执行以下操作:

cut -d <delim> -f <fields> somefile | sponge somefile

9

我认为cut单独使用是不可能的。我在手册页或信息页中找不到它。您可以执行以下操作

mytemp=$(mktemp) && cut -d" " -f1 file > $mytemp && mv $mytemp file

mktemp使您成为一个相对安全的临时文件,可以将其通过管道传输cut到其中。


1

尝试vim-way:

$ ex -s +'%!cut -c 1-10' -cxa file.txt

这将就地编辑文件(首先执行备份)。

另外也可以使用grepsedgawk


0

您可以在POSIX Awk中使用slurp:

cut -b1 file | awk 'BEGIN{RS="";getline<"-";print>ARGV[1]}' file


0

好吧,由于cut产生的输出少于读取的输出,因此您可以执行以下操作:

cut -c1 < file 1<> file

也就是说,将其stdin file在只读模式下file打开,并将其stdout 在读+写模式下打开,而不用截断(<>)。

这样,cut只会覆盖文件本身。但是,它将保留文件的其余部分不变。例如,如果file包含:

foo
bar

输出将变为:

f
b
bar

f\nb\n已经更换foo\n,但bar仍然存在。完成后,您需要截断文件cut

使用ksh93,您可以使用其<>;运算符来执行此操作,该运算符的行为类似于在文件描述符上调用<>的命令是否成功ftruncate()。所以:

cut -c1 < file 1<>; file

对于其他shell,您需要ftruncate()通过其他一些方式来进行操作,例如:

{ cut -c1 < file; perl -e 'truncate STDOUT, tell STDOUT';} 1<> file

尽管perl为此专门调用是有点矫kill过正,尤其是考虑到perl可以轻松完成以下cut任务:

perl -pi -e '$_ = substr($_, 0, 1)' file

请注意,对于所有涉及实际就地重写的方法,如果操作在中途中断,最终将导致文件损坏。使用第二个临时文件可以避免此问题。

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.