process_sub.sh

Download
bash 290 lines 7.3 KB
  1#!/usr/bin/env bash
  2set -euo pipefail
  3
  4# Process Substitution Examples
  5# Demonstrates <(...) and >(...) for advanced I/O patterns
  6
  7echo "=== Process Substitution Demonstrations ==="
  8echo
  9
 10# --- Demo 1: Comparing output of two commands ---
 11demo_diff_commands() {
 12    echo "1. Comparing Output of Two Commands"
 13    echo "------------------------------------"
 14
 15    # Create two sample files
 16    cat > /tmp/file1.txt << EOF
 17apple
 18banana
 19cherry
 20date
 21elderberry
 22EOF
 23
 24    cat > /tmp/file2.txt << EOF
 25apple
 26blueberry
 27cherry
 28date
 29fig
 30EOF
 31
 32    echo "Comparing two files with diff:"
 33    echo
 34
 35    # Traditional approach (requires temp files)
 36    echo "File 1 contents:"
 37    cat /tmp/file1.txt
 38    echo
 39    echo "File 2 contents:"
 40    cat /tmp/file2.txt
 41    echo
 42
 43    # Using process substitution - compare sorted versions
 44    echo "Diff output (process substitution):"
 45    if diff <(sort /tmp/file1.txt) <(sort /tmp/file2.txt); then
 46        echo "Files are identical"
 47    else
 48        echo "(showing differences above)"
 49    fi
 50
 51    echo
 52
 53    # Another example: compare directory listings
 54    echo "Comparing directory contents:"
 55    mkdir -p /tmp/dir1 /tmp/dir2
 56    touch /tmp/dir1/{a,b,c}.txt
 57    touch /tmp/dir2/{b,c,d}.txt
 58
 59    echo "Files only in dir1:"
 60    comm -23 <(ls /tmp/dir1) <(ls /tmp/dir2)
 61
 62    echo "Files only in dir2:"
 63    comm -13 <(ls /tmp/dir1) <(ls /tmp/dir2)
 64
 65    echo "Files in both:"
 66    comm -12 <(ls /tmp/dir1) <(ls /tmp/dir2)
 67
 68    # Cleanup
 69    rm -rf /tmp/file1.txt /tmp/file2.txt /tmp/dir1 /tmp/dir2
 70
 71    echo
 72}
 73
 74# --- Demo 2: Multiple inputs to a command ---
 75demo_multiple_inputs() {
 76    echo "2. Feeding Multiple Inputs to a Command"
 77    echo "----------------------------------------"
 78
 79    # Use paste to combine output from multiple commands
 80    echo "Combining outputs side-by-side with paste:"
 81    paste <(echo -e "1\n2\n3\n4\n5") \
 82          <(echo -e "one\ntwo\nthree\nfour\nfive") \
 83          <(echo -e "I\nII\nIII\nIV\nV")
 84
 85    echo
 86
 87    # Use join to merge related data
 88    echo "Joining related data:"
 89
 90    # Process 1: user IDs and names
 91    # Process 2: user IDs and emails
 92    join <(echo -e "1 Alice\n2 Bob\n3 Charlie") \
 93         <(echo -e "1 alice@example.com\n2 bob@example.com\n3 charlie@example.com")
 94
 95    echo
 96}
 97
 98# --- Demo 3: Avoiding subshell variable issues ---
 99demo_avoid_subshell() {
100    echo "3. Avoiding Subshell Variable Issues"
101    echo "-------------------------------------"
102
103    # Problem: Variables set in pipeline are lost (subshell)
104    echo "Problem - variable in pipeline (lost):"
105    count=0
106    echo -e "a\nb\nc" | while read -r line; do
107        ((count++))
108    done
109    echo "  Count after pipeline: $count (still 0!)"
110
111    echo
112
113    # Solution: Use process substitution (no subshell)
114    echo "Solution - process substitution (preserved):"
115    count=0
116    while read -r line; do
117        ((count++))
118    done < <(echo -e "a\nb\nc")
119    echo "  Count after process sub: $count (correct!)"
120
121    echo
122}
123
124# --- Demo 4: Reading multiple streams simultaneously ---
125demo_multiple_streams() {
126    echo "4. Reading Multiple Streams Simultaneously"
127    echo "------------------------------------------"
128
129    # Read from two sources in parallel
130    echo "Reading two files line-by-line in parallel:"
131
132    # Create sample files
133    seq 1 5 > /tmp/numbers.txt
134    echo -e "one\ntwo\nthree\nfour\nfive" > /tmp/words.txt
135
136    while IFS= read -r num <&3 && IFS= read -r word <&4; do
137        echo "  $num: $word"
138    done 3< /tmp/numbers.txt 4< /tmp/words.txt
139
140    # Cleanup
141    rm -f /tmp/numbers.txt /tmp/words.txt
142
143    echo
144}
145
146# --- Demo 5: Process substitution for writing ---
147demo_write_process_sub() {
148    echo "5. Process Substitution for Writing >(cmd)"
149    echo "-------------------------------------------"
150
151    echo "Splitting output to multiple destinations:"
152
153    # Generate data and send to multiple processors
154    {
155        echo "apple"
156        echo "banana"
157        echo "cherry"
158        echo "date"
159    } | tee >(grep 'a' > /tmp/has_a.txt) \
160            >(grep 'e' > /tmp/has_e.txt) \
161            >(wc -l > /tmp/count.txt) \
162            > /dev/null
163
164    # Small delay to ensure all processes complete
165    sleep 0.1
166
167    echo "Words containing 'a':"
168    cat /tmp/has_a.txt
169
170    echo
171    echo "Words containing 'e':"
172    cat /tmp/has_e.txt
173
174    echo
175    echo "Total word count:"
176    cat /tmp/count.txt
177
178    # Cleanup
179    rm -f /tmp/has_a.txt /tmp/has_e.txt /tmp/count.txt
180
181    echo
182}
183
184# --- Demo 6: Complex data processing pipeline ---
185demo_complex_pipeline() {
186    echo "6. Complex Data Processing Pipeline"
187    echo "------------------------------------"
188
189    # Simulate log file
190    cat > /tmp/access.log << EOF
191192.168.1.1 - - [01/Jan/2024:10:00:00] "GET /index.html HTTP/1.1" 200 1234
192192.168.1.2 - - [01/Jan/2024:10:00:01] "GET /about.html HTTP/1.1" 200 2345
193192.168.1.1 - - [01/Jan/2024:10:00:02] "GET /contact.html HTTP/1.1" 404 0
194192.168.1.3 - - [01/Jan/2024:10:00:03] "POST /api/data HTTP/1.1" 200 5678
195192.168.1.2 - - [01/Jan/2024:10:00:04] "GET /index.html HTTP/1.1" 200 1234
196EOF
197
198    echo "Analyzing log file with process substitution:"
199    echo
200
201    # Compare successful vs failed requests
202    echo "Status code comparison:"
203    paste <(echo "Success (200):") <(grep " 200 " /tmp/access.log | wc -l)
204    paste <(echo "Not Found (404):") <(grep " 404 " /tmp/access.log | wc -l)
205
206    echo
207    echo "Unique IP addresses:"
208    awk '{print $1}' /tmp/access.log | sort -u
209
210    echo
211    echo "Request methods:"
212    awk '{print $6}' /tmp/access.log | tr -d '"' | sort | uniq -c
213
214    # Cleanup
215    rm -f /tmp/access.log
216
217    echo
218}
219
220# --- Demo 7: Named pipe vs process substitution ---
221demo_comparison() {
222    echo "7. Named Pipe vs Process Substitution"
223    echo "--------------------------------------"
224
225    echo "Process substitution creates temporary named pipes:"
226
227    # Show what process substitution looks like
228    echo "Process substitution expands to:"
229    echo "  <(cmd) might expand to: /dev/fd/63"
230
231    # Demonstrate by echoing the expansion
232    bash -c 'echo "Expansion: " <(echo test)'
233
234    echo
235    echo "This is equivalent to creating a named pipe, but automatic!"
236
237    echo
238}
239
240# --- Demo 8: Practical example - log analysis ---
241demo_log_analysis() {
242    echo "8. Practical Example: Log Analysis"
243    echo "-----------------------------------"
244
245    # Generate sample log data
246    {
247        echo "2024-01-01 10:00:00 ERROR Database connection failed"
248        echo "2024-01-01 10:00:05 INFO User login: alice"
249        echo "2024-01-01 10:00:10 WARN High memory usage: 85%"
250        echo "2024-01-01 10:00:15 ERROR Timeout on API call"
251        echo "2024-01-01 10:00:20 INFO User login: bob"
252        echo "2024-01-01 10:00:25 ERROR File not found: data.csv"
253    } > /tmp/application.log
254
255    echo "Log file analysis:"
256    echo
257
258    # Count by log level using process substitution
259    echo "Log level counts:"
260    while IFS= read -r level; do
261        count=$(grep "$level" /tmp/application.log | wc -l)
262        printf "  %-10s %d\n" "$level" "$count"
263    done < <(awk '{print $3}' /tmp/application.log | sort -u)
264
265    echo
266    echo "Error messages only:"
267    grep "ERROR" /tmp/application.log | sed 's/^/  /'
268
269    # Cleanup
270    rm -f /tmp/application.log
271
272    echo
273}
274
275# Main execution
276main() {
277    demo_diff_commands
278    demo_multiple_inputs
279    demo_avoid_subshell
280    demo_multiple_streams
281    demo_write_process_sub
282    demo_complex_pipeline
283    demo_comparison
284    demo_log_analysis
285
286    echo "=== All Demos Complete ==="
287}
288
289main "$@"