0
# Input/Output Handling
1
2
Comprehensive I/O redirection and streaming capabilities including real-time output processing, piping between commands, input feeding, and output capturing. Enables sophisticated data flow control and processing pipelines.
3
4
## Capabilities
5
6
### Real-time Output Processing
7
8
Process command output line-by-line in real-time as it's generated, enabling live monitoring and processing.
9
10
```python { .api }
11
def __call__(self, *args, _out=None, _err=None, **kwargs):
12
"""
13
Execute command with real-time output processing.
14
15
Parameters:
16
- _out: callable = function to process stdout lines
17
- _err: callable = function to process stderr lines
18
19
Returns:
20
str: Complete output (if no callback specified)
21
RunningCommand: Process object (for background execution)
22
"""
23
```
24
25
Usage examples:
26
27
```python
28
import sh
29
30
# Process output line by line
31
def handle_output(line):
32
print(f"LOG: {line.strip()}")
33
34
def handle_error(line):
35
print(f"ERROR: {line.strip()}")
36
37
# Monitor log file in real-time
38
sh.tail("-f", "/var/log/system.log", _out=handle_output, _err=handle_error)
39
40
# Process build output with custom formatting
41
def format_build_output(line):
42
if "ERROR" in line:
43
print(f"🔴 {line.strip()}")
44
elif "WARNING" in line:
45
print(f"🟡 {line.strip()}")
46
elif "SUCCESS" in line:
47
print(f"🟢 {line.strip()}")
48
else:
49
print(f"ℹ️ {line.strip()}")
50
51
sh.make("build", _out=format_build_output)
52
```
53
54
### Output Capturing and Buffering
55
56
Capture and buffer command output for later processing or analysis.
57
58
```python { .api }
59
class RunningCommand:
60
@property
61
def stdout(self) -> str:
62
"""Complete stdout output as string."""
63
64
@property
65
def stderr(self) -> str:
66
"""Complete stderr output as string."""
67
```
68
69
```python { .api }
70
def __call__(self, *args, _tee=False, **kwargs):
71
"""
72
Execute command with output capturing.
73
74
Parameters:
75
- _tee: bool/str = True to echo output to console, "out"/"err" for specific streams
76
77
Returns:
78
str: Command output
79
"""
80
```
81
82
Usage examples:
83
84
```python
85
import sh
86
87
# Capture output for processing
88
result = sh.ps("aux")
89
lines = result.split('\n')
90
python_processes = [line for line in lines if 'python' in line]
91
92
# Capture both stdout and stderr separately
93
proc = sh.grep("pattern", "file.txt", _bg=True)
94
proc.wait()
95
96
stdout_content = proc.stdout
97
stderr_content = proc.stderr
98
99
if proc.exit_code == 0:
100
print("Found matches:", stdout_content)
101
else:
102
print("Errors occurred:", stderr_content)
103
104
# Tee output (show and capture)
105
output = sh.wget("http://example.com/file.zip", _tee=True)
106
# Output is shown on console AND captured in variable
107
```
108
109
### Input Feeding
110
111
Feed input data to commands that read from stdin.
112
113
```python { .api }
114
def __call__(self, *args, _in=None, **kwargs):
115
"""
116
Execute command with input feeding.
117
118
Parameters:
119
- _in: str/bytes/file/iterable = input data to feed to command
120
121
Returns:
122
str: Command output
123
"""
124
```
125
126
Usage examples:
127
128
```python
129
import sh
130
131
# Feed string input
132
result = sh.grep("pattern", _in="line1\nline2\npattern here\nline4")
133
print(result)
134
135
# Feed file content
136
with open("input.txt", "r") as f:
137
output = sh.sort(_in=f)
138
139
# Feed data from another command's output
140
log_data = sh.cat("/var/log/system.log")
141
filtered = sh.grep("ERROR", _in=log_data)
142
143
# Feed bytes data
144
binary_data = b"binary content here"
145
result = sh.hexdump(_in=binary_data)
146
147
# Feed iterative data
148
def data_generator():
149
for i in range(1000):
150
yield f"line {i}\n"
151
152
sh.wc("-l", _in=data_generator())
153
```
154
155
### Command Piping
156
157
Chain commands together using pipes to create processing pipelines.
158
159
```python { .api }
160
def __call__(self, *args, _piped=True, **kwargs):
161
"""
162
Execute command with piping enabled.
163
164
Parameters:
165
- _piped: bool = True to enable piping output to other commands
166
167
Returns:
168
RunningCommand: Command object that can be piped to others
169
"""
170
```
171
172
Usage examples:
173
174
```python
175
import sh
176
177
# Basic piping
178
result = sh.grep(sh.ps("aux"), "python")
179
print(result)
180
181
# Complex pipeline
182
pipeline = sh.sort(sh.uniq(sh.cut(sh.cat("data.txt"), "-f", "2")))
183
print(pipeline)
184
185
# Multi-stage processing
186
logs = sh.cat("/var/log/system.log")
187
errors = sh.grep(logs, "ERROR")
188
recent_errors = sh.tail(errors, "-n", "10")
189
print(recent_errors)
190
191
# Pipeline with formatting
192
def format_ps_output(line):
193
parts = line.split()
194
if len(parts) > 10:
195
return f"PID: {parts[1]}, CMD: {parts[10]}"
196
return line
197
198
formatted = sh.ps("aux", _out=format_ps_output)
199
python_procs = sh.grep(formatted, "python")
200
```
201
202
### Stream Redirection
203
204
Redirect command streams to files or other destinations.
205
206
```python { .api }
207
def __call__(self, *args, _out_bufsize=0, _err_bufsize=0, **kwargs):
208
"""
209
Execute command with stream buffering control.
210
211
Parameters:
212
- _out_bufsize: int = stdout buffer size (0=unbuffered, 1=line-buffered)
213
- _err_bufsize: int = stderr buffer size
214
215
Returns:
216
str: Command output
217
"""
218
```
219
220
Usage examples:
221
222
```python
223
import sh
224
from io import StringIO
225
226
# Redirect to file-like objects
227
stdout_buffer = StringIO()
228
stderr_buffer = StringIO()
229
230
def write_stdout(line):
231
stdout_buffer.write(line)
232
233
def write_stderr(line):
234
stderr_buffer.write(line)
235
236
sh.make("build", _out=write_stdout, _err=write_stderr)
237
238
# Get captured content
239
build_output = stdout_buffer.getvalue()
240
build_errors = stderr_buffer.getvalue()
241
242
# Unbuffered output for real-time processing
243
sh.tail("-f", "/var/log/system.log", _out_bufsize=0, _out=lambda line: print(line, end=''))
244
```
245
246
### Advanced I/O Patterns
247
248
Complex I/O handling patterns for sophisticated data processing workflows.
249
250
```python
251
import sh
252
import threading
253
import queue
254
255
# Async output processing
256
output_queue = queue.Queue()
257
258
def queue_output(line):
259
output_queue.put(line.strip())
260
261
def process_output():
262
while True:
263
try:
264
line = output_queue.get(timeout=1)
265
# Process line here
266
print(f"Processed: {line}")
267
output_queue.task_done()
268
except queue.Empty:
269
break
270
271
# Start output processor thread
272
processor_thread = threading.Thread(target=process_output)
273
processor_thread.start()
274
275
# Run command with queued output
276
sh.find("/", "-name", "*.log", _out=queue_output, _bg=True)
277
278
# Wait for processing to complete
279
processor_thread.join()
280
281
# Filtered piping with custom logic
282
class FilteredPipe:
283
def __init__(self, filter_func):
284
self.filter_func = filter_func
285
self.buffer = []
286
287
def __call__(self, line):
288
if self.filter_func(line):
289
self.buffer.append(line.strip())
290
291
def get_results(self):
292
return '\n'.join(self.buffer)
293
294
# Filter for Python processes only
295
python_filter = FilteredPipe(lambda line: 'python' in line.lower())
296
sh.ps("aux", _out=python_filter)
297
298
python_processes = python_filter.get_results()
299
print("Python processes:")
300
print(python_processes)
301
```
302
303
### Binary Data Handling
304
305
Handle binary data streams and non-text command output.
306
307
```python { .api }
308
def __call__(self, *args, _decode_errors='strict', **kwargs):
309
"""
310
Execute command with binary data handling.
311
312
Parameters:
313
- _decode_errors: str = how to handle decode errors ('strict', 'ignore', 'replace')
314
315
Returns:
316
str/bytes: Command output
317
"""
318
```
319
320
Usage examples:
321
322
```python
323
import sh
324
325
# Handle binary output
326
binary_data = sh.cat("/bin/ls", _decode_errors='ignore')
327
print(f"Binary data length: {len(binary_data)}")
328
329
# Process binary streams
330
def handle_binary_chunk(chunk):
331
# Process binary data chunk
332
if isinstance(chunk, bytes):
333
print(f"Received {len(chunk)} bytes")
334
else:
335
print(f"Text chunk: {chunk[:50]}...")
336
337
# Commands that output binary data
338
sh.dd("if=/dev/urandom", "count=10", "bs=1024", _out=handle_binary_chunk)
339
340
# Handle mixed text/binary output
341
sh.hexdump("-C", "/bin/ls", _decode_errors='replace', _out=lambda line: print(line[:80]))
342
```