article-athas-shell-redirections.mw - tgtimes - The Gopher Times | |
git clone git://bitreich.org/tgtimes git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws… | |
Log | |
Files | |
Refs | |
Tags | |
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. |