0

Note: I am particularly looking for a coding hack, not for an alternative solution. I am aware that awk, sed etc. can do this inline edit just fine.

$ echo '1' > test
$ cat test > test
$ cat test
$ 

Is there a way, to somehow make the second command output the original contents (1 in this case)? Again, I am looking for a hack which will work without visibly having to use a secondary file (using a secondary file in the background is fine). Another question on this forum solely focused on alternative solutions which is not what I am looking for.

Roel Van de Paar
  • 2,111
  • 1
  • 24
  • 38
  • Note that _you have to store the content somewhere_, and the `>test` is executed the command it's attached to begins execution. If your content will never be larger than can fit in memory, this is doable; if you can't guarantee that, it isn't -- solutions that work around it will be using a file in the background somewhere. (For that matter, `sed -i` _also_ uses a file in the background; it's the standard/best-practice solution). – Charles Duffy Jun 24 '22 at 23:41
  • Anyhow -- can you explain _why_ you're doing this? If you're working on a filesystem like procfs or sysfs where only specific, known filenames are valid and you can't create arbitrary files with other names, that suggests a specific set of solutions. If we don't know what practical constraints lead you to be unable to use the standard best-practice approach, we don't know if the solutions we suggest will work in your environment. – Charles Duffy Jun 24 '22 at 23:46
  • 2
    `cat test | sponge test`? – Cyrus Jun 24 '22 at 23:54
  • @CharlesDuffy my question is genuine, I need it in many practical situations (this situation often occurs when coding bash scripts), and it is answerable, as Cyrus and Barmar proved. – Roel Van de Paar Jun 25 '22 at 00:22
  • `sponge` creates a temporary file. Look at the implementation, or even just read its manual. I don't think I've seen an explanation of why "without using a secondary file" is part of the spec, and that's what I was asking for above. – Charles Duffy Jun 25 '22 at 12:07
  • To be clear, if you had asked how to do this without writing code that renames a temporary file yourself, I would have just closed the question as a duplicate of an existing one that already has answers recommending `sponge`. But you said without a secondary file at all, making this a different question -- but haven't, as yet, provided a practical explanation for the value of making it distinct in that way. – Charles Duffy Jun 25 '22 at 12:15
  • See f/e [Best way to modify a file when using pipes](https://stackoverflow.com/a/31325932/14122) as an example of a question that doesn't have the "without a temporary file" qualifier on it, and has answers suggesting both sponge and native-shell equivalents. – Charles Duffy Jun 25 '22 at 12:49
  • Okay I've updated the question to better reflect what I had in mind. Please cleanup all these comments. – Roel Van de Paar Jun 27 '22 at 00:44

3 Answers3

3

You can store the content in a shell variable rather than a file.

var=$(<test)
printf "%s\n" "$var" > test

Note that this might only work for text files, not binary files. If you need to deal with them you can use encoding/decoding commands in the pipeline.

You can't do it without storing the data somewhere. When you redirect output to a file, the shell truncates the file immediately. If you use a pipeline, the commands in the pipeline run concurrently with the shell, and it's unpredictable which will run first -- the shell truncating the file or the command that tries to read from it.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 1
    Of course, one can transiently transform a binary file into a text file by injecting `uuencode`/`uudecode`, `base64`/`base64 -D`, &c into the pipeline. – Charles Duffy Jun 24 '22 at 23:44
1

With thanks to the comment made by @Cyrus to the original question

$ sudo apt install moreutils
$ echo '1' > test
$ cat test | sponge test
$ cat test
1

It does require installing an extra package and pre-checking for the binary using something like where sponge to check if it is installed.

Roel Van de Paar
  • 2,111
  • 1
  • 24
  • 38
  • `sponge` uses a secondary file. Quoting its manual: *When possible, sponge creates or updates the output file atomically by renaming a temp file into place.* – Charles Duffy Jun 25 '22 at 12:09
0

if you happen to use macos, if the file isn't too gargantuan, you can always follow these steps :

  1. perform the edits
  2. pipe it to the clipboard (or "pasteboard" in mac lingo)
  3. paste it back to original file name

|

{... edits to file1 ...} | pbcopy; pbpaste > file1 
RARE Kpop Manifesto
  • 2,453
  • 3
  • 11