article-athas-shell-redirections.mw - tgtimes - The Gopher Times HTML git clone git://bitreich.org/tgtimes git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/tgtimes DIR Log DIR Files DIR Refs DIR Tags DIR README --- article-athas-shell-redirections.mw (2204B) --- 1 .SH athas 2 Shell Redirections 3 . 4 .PP 5 Newcomers to the Unix shell quickly encounter handy tools such as 6 sed(1) and sort(1). This command prints the lines of the given file 7 to stdout, in sorted order: 8 . 9 .DS 10 $ sort numbers 11 .DE 12 . 13 .PP 14 Soon after, newcomers will also encounter shell redirection, by which 15 the output of these tools can conveniently be read from or stored in 16 files: 17 . 18 .DS 19 $ sort < numbers > numbers_sorted 20 .DE 21 . 22 .PP 23 Our new user, fascinated by the modularity of the Unix shell, may then 24 try the rather obvious possibility of having the input and output file 25 be the same: 26 . 27 .DS 28 $ sort < numbers > numbers 29 .DE 30 . 31 .PP 32 But disaster strikes: the file is empty! The user has lost their 33 precious collection of numbers - let's hope they had a backup. Losing 34 data this way is almost a rite of passage for Unix users, but let us 35 spell out the reason for those who have yet to hurt themselves this 36 way. 37 . 38 .PP 39 When the Unix shell evaluates a command, it starts by processing the 40 redirection operators - that's the '>' and '<' above. While '<' just 41 opens the file, '>' *truncates* the file in-place as it is opened for 42 reading! This means that the 'sort' process will dutifully read an 43 empty file, sort its non-existent lines, and correctly produce empty 44 output. 45 . 46 .PP 47 Some programs can be asked to write their output directly to files 48 instead of using shell redirection (sed(1) has '-i', and for sort(1) 49 we can use '-o'), but this is not a general solution, and does not 50 work for pipelines. Another solution is to use the sponge(1) tool 51 from the "moreutils" project, which stores its standard input in 52 memory before finally writing it to a file: 53 . 54 .DS 55 $ sort < numbers | sponge numbers 56 .DE 57 . 58 .PP 59 The most interesting solution is to take advantage of subshells, the 60 shell evaluation order, and Unix file systems semantics. When we 61 delete a file in Unix, it is removed from the file system, but any 62 file descriptors referencing the file remain valid. We can exploit 63 this behaviour to delete the input file *after* directing the input, 64 but *before* redirecting the output: 65 . 66 .DS 67 $ (rm numbers && sort > numbers) < numbers 68 .DE 69 . 70 .PP 71 This approach requires no dependencies and will work in any Unix 72 shell.