38

I've got a script that calls grep to process a text file. Currently I am doing something like this.

$ grep 'SomeRegEx' myfile.txt > myfile.txt.temp
$ mv myfile.txt.temp myfile.txt

I'm wondering if there is any way to do in-place processing, as in store the results to the same original file without having to create a temporary file and then replace the original with the temp file when processing is done.

Of course I welcome comments as to why this should or should not be done, but I'm mainly interested in whether it can be done. In this example I'm using grep, but I'm interested about Unix tools in general. Thanks!

kenorb
  • 155,785
  • 88
  • 678
  • 743
Daniel Standage
  • 8,136
  • 19
  • 69
  • 116

9 Answers9

36

sponge (in moreutils package in Debian/Ubuntu) reads input till EOF and writes it into file, so you can grep file and write it back to itself.

Like this:

grep 'pattern' file | sponge file
Camille Goudeseune
  • 2,934
  • 2
  • 35
  • 56
Alexey
  • 506
  • 4
  • 5
19

Perl has the -i switch, so does sed and Ruby

sed -i.bak -n '/SomeRegex/p' file

ruby -i.bak -ne 'print if /SomeRegex/' file

But note that all it ever does is creating "temp" files at the back end which you think you don't see, that's all.

Other ways, besides grep

awk

awk '/someRegex/' file > t && mv t file

bash

while read -r line;do case "$line" in *someregex*) echo "$line";;esac;done <file > t && mv t file
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • 1
    How do the awk and bash examples improve on the original grep, other than `&&` instead of `;`? These still explicitly create a temporary file. – Camille Goudeseune Oct 18 '17 at 15:22
4

No, in general it can't be done in Unix like this. You can only create/truncate (with >) or append to a file (with >>). Once truncated, the old contents would be lost.

The Archetypal Paul
  • 41,321
  • 20
  • 104
  • 134
4

In general, this can't be done. But Perl has the -i switch:

perl -i -ne 'print if /SomeRegEx/' myfile.txt

Writing -i.bak will cause the original to be saved in myfile.txt.bak.

(Of course internally, Perl just does basically what you're already doing -- there's no special magic involved.)

j_random_hacker
  • 50,331
  • 10
  • 105
  • 169
1

To edit file in-place using vim-way, try:

$ ex -s +'%!grep foo' -cxa myfile.txt

Alternatively use sed or gawk.

Community
  • 1
  • 1
kenorb
  • 155,785
  • 88
  • 678
  • 743
1

Most installations of sed can do in-place editing, check the man page, you probably want the -i flag.

High Performance Mark
  • 77,191
  • 7
  • 105
  • 161
-1

Store in a variable and then assign it to the original file:

A=$(cat aux.log | grep 'Something') && echo "${A}" > aux.log
  • Did you actually try this command? The `>` redirect truncates the input file before the `cat` command can read any input. – Daniel Standage Nov 09 '18 at 21:01
  • 1
    Hi, please avoid providing code only answers. Try to include an explanation of why the code/command you proposed solves the problem, or what caused it in the first place so the OP or someone with a similar problem can understand what to do. – Fabulous Nov 10 '18 at 01:37
-2

Take a look at my slides "Field Guide To the Perl Command-Line Options" at http://petdance.com/perl/command-line-options.pdf for more ideas on what you can do in place with Perl.

Andy Lester
  • 91,102
  • 13
  • 100
  • 152
-2

cat myfile.txt | grep 'sometext' > myfile.txt

This will find sometext in myfile.txt and save it back to myfile.txt, this will accomplish what you want. Not sure about regex, but it does work for text.

2anoyu
  • 11
  • 2
  • 1
    This will actually truncate the `myfile.txt`! Bash will open the file for writing, pass it to grep as std out and cat will read just an empty file. – Hrobky Feb 07 '21 at 18:09