0
# Process Management
1
2
Advanced process control including background execution, process monitoring, signal handling, and process lifecycle management. Provides comprehensive control over long-running commands and process interactions.
3
4
## Capabilities
5
6
### Process Lifecycle Control
7
8
Manage the lifecycle of running processes with methods to wait, terminate, and kill processes.
9
10
```python { .api }
11
class RunningCommand:
12
def wait(self):
13
"""
14
Wait for the process to complete.
15
16
Returns:
17
None
18
19
Raises:
20
ErrorReturnCode: If process exits with non-zero status
21
"""
22
23
def kill(self):
24
"""
25
Forcefully kill the process with SIGKILL.
26
27
Returns:
28
None
29
"""
30
31
def terminate(self):
32
"""
33
Gracefully terminate the process with SIGTERM.
34
35
Returns:
36
None
37
"""
38
```
39
40
Usage examples:
41
42
```python
43
import sh
44
import time
45
46
# Start a long-running process
47
proc = sh.sleep(30, _bg=True)
48
49
# Check if we need to cancel it
50
time.sleep(5)
51
if some_condition:
52
proc.terminate() # Try graceful termination first
53
time.sleep(2)
54
if proc.is_alive():
55
proc.kill() # Force kill if still running
56
57
# Wait for normal completion
58
try:
59
proc.wait()
60
print("Process completed normally")
61
except sh.ErrorReturnCode as e:
62
print(f"Process failed: {e}")
63
```
64
65
### Process Status Monitoring
66
67
Monitor process status and retrieve process information.
68
69
```python { .api }
70
class RunningCommand:
71
def is_alive(self) -> bool:
72
"""
73
Check if the process is still running.
74
75
Returns:
76
bool: True if process is running, False otherwise
77
"""
78
79
@property
80
def pid(self) -> int:
81
"""Process ID of the running command."""
82
83
@property
84
def exit_code(self) -> int:
85
"""Exit code of the process (None if still running)."""
86
```
87
88
Usage examples:
89
90
```python
91
import sh
92
import time
93
94
# Monitor multiple background processes
95
processes = [
96
sh.ping("-c", "10", "google.com", _bg=True),
97
sh.wget("http://example.com/large-file.zip", _bg=True),
98
sh.rsync("-av", "/source/", "/dest/", _bg=True)
99
]
100
101
# Monitor all processes
102
while any(proc.is_alive() for proc in processes):
103
for i, proc in enumerate(processes):
104
if proc.is_alive():
105
print(f"Process {i} (PID {proc.pid}) still running...")
106
else:
107
print(f"Process {i} completed with exit code {proc.exit_code}")
108
time.sleep(5)
109
110
print("All processes completed")
111
```
112
113
### Signal Handling
114
115
Send signals to running processes for advanced process control.
116
117
```python { .api }
118
class RunningCommand:
119
def signal(self, sig):
120
"""
121
Send a signal to the process.
122
123
Parameters:
124
- sig: int or signal constant (e.g., signal.SIGUSR1)
125
126
Returns:
127
None
128
"""
129
```
130
131
Usage examples:
132
133
```python
134
import sh
135
import signal
136
import time
137
138
# Start a process that handles signals
139
proc = sh.tail("-f", "/var/log/system.log", _bg=True)
140
141
# Let it run for a while
142
time.sleep(10)
143
144
# Send a custom signal (if the process handles it)
145
proc.signal(signal.SIGUSR1)
146
147
# Send SIGTERM for graceful shutdown
148
proc.signal(signal.SIGTERM)
149
150
# Wait a bit, then force kill if needed
151
time.sleep(2)
152
if proc.is_alive():
153
proc.signal(signal.SIGKILL)
154
```
155
156
### Process Groups and Session Management
157
158
Manage process groups and sessions for complex process hierarchies.
159
160
```python { .api }
161
def __call__(self, *args, _new_session=False, **kwargs):
162
"""
163
Execute command with process group control.
164
165
Parameters:
166
- _new_session: bool = True to start in new session
167
168
Returns:
169
RunningCommand: Process object
170
"""
171
```
172
173
Usage examples:
174
175
```python
176
import sh
177
178
# Start process in new session (detached from parent)
179
daemon_proc = sh.python("daemon.py", _bg=True, _new_session=True)
180
181
# This process will continue even if parent script exits
182
print(f"Daemon started with PID {daemon_proc.pid}")
183
184
# The daemon is now independent of this script's lifecycle
185
```
186
187
### Timeout Management
188
189
Handle process timeouts and long-running command management.
190
191
```python { .api }
192
def __call__(self, *args, _timeout=None, **kwargs):
193
"""
194
Execute command with timeout.
195
196
Parameters:
197
- _timeout: int/float = seconds to wait before killing process
198
199
Returns:
200
str: Command output
201
202
Raises:
203
TimeoutException: If command exceeds timeout
204
"""
205
```
206
207
Usage examples:
208
209
```python
210
import sh
211
212
# Set timeout for potentially hanging commands
213
try:
214
# Network command that might hang
215
result = sh.curl("http://slow-server.com", _timeout=30)
216
print("Download completed:", result)
217
except sh.TimeoutException:
218
print("Download timed out after 30 seconds")
219
220
# Background process with timeout monitoring
221
proc = sh.sleep(60, _bg=True)
222
223
start_time = time.time()
224
timeout = 10
225
226
while proc.is_alive():
227
if time.time() - start_time > timeout:
228
print("Manually timing out process")
229
proc.terminate()
230
break
231
time.sleep(1)
232
```
233
234
### Process Resource Management
235
236
Monitor and control process resources.
237
238
```python { .api }
239
class RunningCommand:
240
@property
241
def process(self):
242
"""Access to underlying subprocess.Popen object."""
243
```
244
245
Usage examples:
246
247
```python
248
import sh
249
import psutil # External library for extended process info
250
251
# Get detailed process information
252
proc = sh.find("/", "-name", "*.log", _bg=True)
253
254
# Access underlying process for advanced control
255
popen = proc.process
256
print(f"Process memory usage: {popen.memory_info()}")
257
258
# Use with psutil for extended monitoring
259
if hasattr(psutil, 'Process'):
260
ps_proc = psutil.Process(proc.pid)
261
print(f"CPU usage: {ps_proc.cpu_percent()}")
262
print(f"Memory usage: {ps_proc.memory_info()}")
263
```
264
265
### Batch Process Management
266
267
Manage multiple related processes as a group.
268
269
```python
270
import sh
271
import time
272
273
class ProcessManager:
274
def __init__(self):
275
self.processes = []
276
277
def start(self, command, *args, **kwargs):
278
"""Start a process and add to management."""
279
proc = command(*args, _bg=True, **kwargs)
280
self.processes.append(proc)
281
return proc
282
283
def wait_all(self):
284
"""Wait for all processes to complete."""
285
for proc in self.processes:
286
proc.wait()
287
288
def kill_all(self):
289
"""Kill all running processes."""
290
for proc in self.processes:
291
if proc.is_alive():
292
proc.kill()
293
294
def status(self):
295
"""Get status of all processes."""
296
running = sum(1 for p in self.processes if p.is_alive())
297
total = len(self.processes)
298
return f"{running}/{total} processes running"
299
300
# Usage
301
manager = ProcessManager()
302
303
# Start multiple related processes
304
manager.start(sh.rsync, "-av", "/data1/", "/backup/")
305
manager.start(sh.rsync, "-av", "/data2/", "/backup/")
306
manager.start(sh.rsync, "-av", "/data3/", "/backup/")
307
308
# Monitor progress
309
while any(p.is_alive() for p in manager.processes):
310
print(manager.status())
311
time.sleep(5)
312
313
print("All backups completed")
314
```