6

Solutions that I have come across for replacing the contents of an input file with converted output involve using a temp file or the sponge utility.

Stephane Chazelas's answer here indicates another way involving opening the file in read-write mode as below.

tr ' ' '\t' < file 1<> file

How does this actually work without corrupting the file in question?

2 Answers 2

9

This only works because tr does not change the file size.

1<>file opens file as standard output in overwrite mode. (<> is called read/write mode, but since few programs read stdout, it's more useful to focus on what it actually does.)

Normally, when you redirect output (>file), the file is opened in "write" mode, which causes it to either be created or emptied. Another common option is >>file, "append" mode, which skips the step where the file is emptied, but puts all output at the end. 1<>file also skips emptying the file, but it puts the write cursor at the beginning of the file. (You need the 1 because <> defaults to redirecting stdin, not stdout).

This is only very occasionally useful, since very few utilities are so precise in their modification. Another case would be a search and replace where the replacement is exactly the same length as the original. (A shorter replacement wouldn't work either, because the file is not truncated at the end; if the output is shorter than the original, you'd end up with whatever used to be at the end of the file still being at the end of the file.)

3

When you use the syntax < file that opens the file as read only, and reads the contents of the lines in the file into standard in (STDIN aka. file descriptor 0). Afterwards the standard out (STDOUT aka. file descriptor 1) is opened as read + write (the 1<>) and the contents of the lines are written out thusly.

You can read more about I/O + Bash in this section, Chapter 20. I/O Redirection, of the Advanced Bash-Scripting Guide.

excerpt

   [j]<>filename
      #  Open file "filename" for reading and writing,
      #+ and assign file descriptor "j" to it.
      #  If "filename" does not exist, create it.
      #  If file descriptor "j" is not specified, default to fd 0, stdin.
      #
      #  An application of this is writing at a specified place in a file. 
      echo 1234567890 > File    # Write string to "File".
      exec 3<> File             # Open "File" and assign fd 3 to it.
      read -n 4 <&3             # Read only 4 characters.
      echo -n . >&3             # Write a decimal point there.
      exec 3>&-                 # Close fd 3.
      cat File                  # ==> 1234.67890
      #  Random access, by golly.

Same file opened multiple times, what?

Take a look at how file descriptors work in this U&L Q&A titled: How can same fd in different processes point to the same file?. It covers how the same file can be opened multiple times.

2
  • thanks and +1. I accepted rici's answer because it cleared a cobweb in my understanding
    – iruvar
    Commented Aug 20, 2013 at 17:00
  • @1_CR - thanks for letting me know. NP, you accept the one that helps you the most or makes the most sense. I added mine to help you but also to try and flesh out the topic better and also provide linkages between your Q and the actual documentation that covers it.
    – slm
    Commented Aug 20, 2013 at 17:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .