1#!/usr/bin/env bash
2set -euo pipefail
3
4# File Descriptor Demonstrations
5# Shows advanced usage of file descriptors for I/O redirection
6
7echo "=== File Descriptor Demonstrations ==="
8echo
9
10# --- Demo 1: Custom file descriptors ---
11demo_custom_fd() {
12 echo "1. Custom File Descriptors"
13 echo "--------------------------"
14
15 local output_file="/tmp/fd_demo_output.txt"
16 local error_file="/tmp/fd_demo_error.txt"
17
18 # Open custom file descriptors
19 exec 3>"$output_file" # FD 3 for normal output
20 exec 4>"$error_file" # FD 4 for error output
21
22 echo "Writing to FD 3 (output file)" >&3
23 echo "Writing to FD 4 (error file)" >&4
24
25 echo "More output data" >&3
26 echo "More error data" >&4
27
28 # Close custom file descriptors
29 exec 3>&-
30 exec 4>&-
31
32 echo "Files created:"
33 echo " Output file: $output_file"
34 cat "$output_file"
35
36 echo
37 echo " Error file: $error_file"
38 cat "$error_file"
39
40 # Cleanup
41 rm -f "$output_file" "$error_file"
42
43 echo
44}
45
46# --- Demo 2: Redirecting stderr separately ---
47demo_separate_stderr() {
48 echo "2. Redirecting Stderr Separately"
49 echo "---------------------------------"
50
51 local stdout_file="/tmp/stdout.txt"
52 local stderr_file="/tmp/stderr.txt"
53
54 # Function that outputs to both stdout and stderr
55 mixed_output() {
56 echo "This goes to stdout"
57 echo "This goes to stderr" >&2
58 echo "More stdout"
59 echo "More stderr" >&2
60 }
61
62 echo "Calling function with mixed output..."
63 mixed_output 1>"$stdout_file" 2>"$stderr_file"
64
65 echo
66 echo "STDOUT contents:"
67 cat "$stdout_file"
68
69 echo
70 echo "STDERR contents:"
71 cat "$stderr_file"
72
73 # Cleanup
74 rm -f "$stdout_file" "$stderr_file"
75
76 echo
77}
78
79# --- Demo 3: Swapping stdout and stderr ---
80demo_swap_stdout_stderr() {
81 echo "3. Swapping Stdout and Stderr"
82 echo "-----------------------------"
83
84 # Function with mixed output
85 test_output() {
86 echo "STDOUT message"
87 echo "STDERR message" >&2
88 }
89
90 echo "Normal output:"
91 test_output 2>&1 | sed 's/^/ /'
92
93 echo
94 echo "With stdout and stderr swapped (3>&1 1>&2 2>&3):"
95 (test_output 3>&1 1>&2 2>&3) 2>&1 | sed 's/^/ /'
96
97 echo
98}
99
100# --- Demo 4: Logging to both console and file ---
101demo_tee_with_fd() {
102 echo "4. Logging to Console and File Simultaneously"
103 echo "----------------------------------------------"
104
105 local log_file="/tmp/dual_output.log"
106
107 # Open log file on FD 3
108 exec 3>"$log_file"
109
110 # Function to log to both console and file
111 dual_log() {
112 local message="$*"
113 echo "$message" | tee /dev/fd/3
114 }
115
116 dual_log "This message appears on console and in log file"
117 dual_log "Second message"
118 dual_log "Third message"
119
120 # Close log file
121 exec 3>&-
122
123 echo
124 echo "Log file contents:"
125 cat "$log_file"
126
127 # Cleanup
128 rm -f "$log_file"
129
130 echo
131}
132
133# --- Demo 5: Reading from and writing to same file descriptor ---
134demo_readwrite_fd() {
135 echo "5. Read/Write File Descriptor"
136 echo "-----------------------------"
137
138 local data_file="/tmp/rw_data.txt"
139
140 # Create initial data
141 cat > "$data_file" << EOF
142Line 1: Original
143Line 2: Original
144Line 3: Original
145EOF
146
147 echo "Original file:"
148 cat "$data_file"
149
150 echo
151 echo "Opening file for read/write on FD 3..."
152
153 # Open file for reading and writing
154 exec 3<> "$data_file"
155
156 # Read first line
157 read -r line <&3
158 echo "Read: $line"
159
160 # Write to file (appends)
161 echo "Line 4: Added via FD 3" >&3
162
163 # Close FD
164 exec 3>&-
165
166 echo
167 echo "Modified file:"
168 cat "$data_file"
169
170 # Cleanup
171 rm -f "$data_file"
172
173 echo
174}
175
176# --- Demo 6: Saving and restoring stdout ---
177demo_save_restore_stdout() {
178 echo "6. Saving and Restoring Stdout"
179 echo "-------------------------------"
180
181 local temp_file="/tmp/redirected_output.txt"
182
183 echo "This goes to original stdout"
184
185 # Save original stdout to FD 6
186 exec 6>&1
187
188 # Redirect stdout to file
189 exec 1>"$temp_file"
190
191 echo "This goes to the file (not visible on console)"
192 echo "Another line to the file"
193
194 # Restore original stdout
195 exec 1>&6
196
197 # Close FD 6
198 exec 6>&-
199
200 echo "This goes to original stdout again"
201
202 echo
203 echo "File contents:"
204 cat "$temp_file"
205
206 # Cleanup
207 rm -f "$temp_file"
208
209 echo
210}
211
212# --- Demo 7: Here-document with file descriptor ---
213demo_heredoc_fd() {
214 echo "7. Here-document with File Descriptor"
215 echo "--------------------------------------"
216
217 # Assign here-document to FD 3
218 exec 3<<EOF
219First line from here-doc
220Second line from here-doc
221Third line from here-doc
222EOF
223
224 echo "Reading from here-document via FD 3:"
225 while IFS= read -r line <&3; do
226 echo " > $line"
227 done
228
229 # Close FD 3
230 exec 3>&-
231
232 echo
233}
234
235# --- Demo 8: Noclobber and forcing overwrite ---
236demo_noclobber() {
237 echo "8. Noclobber and Forcing Overwrite"
238 echo "-----------------------------------"
239
240 local test_file="/tmp/noclobber_test.txt"
241
242 echo "Original content" > "$test_file"
243
244 # Enable noclobber
245 set -C
246
247 echo "Noclobber enabled (set -C)"
248 echo "Trying to overwrite existing file..."
249
250 if echo "Overwrite attempt" > "$test_file" 2>/dev/null; then
251 echo " ✗ Should have failed!"
252 else
253 echo " ✓ Prevented overwrite (as expected)"
254 fi
255
256 echo "Forcing overwrite with >|..."
257 echo "Forced overwrite" >| "$test_file"
258 echo " ✓ Success"
259
260 # Disable noclobber
261 set +C
262
263 echo "Noclobber disabled (set +C)"
264 echo "Normal overwrite works again" > "$test_file"
265 echo " ✓ Overwrite successful"
266
267 # Cleanup
268 rm -f "$test_file"
269
270 echo
271}
272
273# Main execution
274main() {
275 demo_custom_fd
276 demo_separate_stderr
277 demo_swap_stdout_stderr
278 demo_tee_with_fd
279 demo_readwrite_fd
280 demo_save_restore_stdout
281 demo_heredoc_fd
282 demo_noclobber
283
284 echo "=== All Demos Complete ==="
285}
286
287main "$@"