1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! `proc by` - Filter processes by name
//!
//! Examples:
//! proc by node # Processes named 'node'
//! proc by node --in . # Node processes in current directory
//! proc by node --min-cpu 5 # Node processes using >5% CPU
//! proc by "my app" # Processes with spaces in name
use crate::core::{resolve_in_dir, sort_processes, Process, ProcessStatus, SortKey};
use crate::error::Result;
use crate::ui::Printer;
use clap::Args;
use std::path::PathBuf;
/// Filter processes by name
#[derive(Args, Debug)]
pub struct ByCommand {
/// Process name or pattern to match
pub name: String,
/// Filter by directory (defaults to current directory if no path given)
#[arg(long = "in", short = 'i', num_args = 0..=1, default_missing_value = ".")]
pub in_dir: Option<String>,
/// Only show processes using more than this CPU %
#[arg(long)]
pub min_cpu: Option<f32>,
/// Only show processes using more than this memory (MB)
#[arg(long)]
pub min_mem: Option<f64>,
/// Filter by status: running, sleeping, stopped, zombie
#[arg(long)]
pub status: Option<String>,
/// Only show processes running longer than this (seconds)
#[arg(long)]
pub min_uptime: Option<u64>,
/// Only show children of this parent PID
#[arg(long)]
pub parent: Option<u32>,
/// Output as JSON
#[arg(long, short = 'j')]
pub json: bool,
/// Show verbose output with command line, cwd, and parent PID
#[arg(long, short = 'v')]
pub verbose: bool,
/// Limit the number of results
#[arg(long, short = 'n')]
pub limit: Option<usize>,
/// Sort by: cpu, mem, pid, name
#[arg(long, short = 's', value_enum, default_value_t = SortKey::Cpu)]
pub sort: SortKey,
}
impl ByCommand {
/// Executes the by command, listing processes matching the name filter.
pub fn execute(&self) -> Result<()> {
let printer = Printer::from_flags(self.json, self.verbose);
// Get processes by name
let mut processes = Process::find_by_name(&self.name)?;
// Resolve --in filter path
let in_dir_filter = resolve_in_dir(&self.in_dir);
// Apply filters
processes.retain(|p| {
// Directory filter (--in)
if let Some(ref dir_path) = in_dir_filter {
if let Some(ref proc_cwd) = p.cwd {
let proc_path = PathBuf::from(proc_cwd);
if !proc_path.starts_with(dir_path) {
return false;
}
} else {
return false;
}
}
// CPU filter
if let Some(min_cpu) = self.min_cpu {
if p.cpu_percent < min_cpu {
return false;
}
}
// Memory filter
if let Some(min_mem) = self.min_mem {
if p.memory_mb < min_mem {
return false;
}
}
// Status filter
if let Some(ref status) = self.status {
let status_match = match status.to_lowercase().as_str() {
"running" => matches!(p.status, ProcessStatus::Running),
"sleeping" | "sleep" => matches!(p.status, ProcessStatus::Sleeping),
"stopped" | "stop" => matches!(p.status, ProcessStatus::Stopped),
"zombie" => matches!(p.status, ProcessStatus::Zombie),
_ => true,
};
if !status_match {
return false;
}
}
// Uptime filter
if let Some(min_uptime) = self.min_uptime {
if let Some(start_time) = p.start_time {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0);
if now.saturating_sub(start_time) < min_uptime {
return false;
}
} else {
return false;
}
}
// Parent PID filter
if let Some(ppid) = self.parent {
if p.parent_pid != Some(ppid) {
return false;
}
}
true
});
// Sort processes
sort_processes(&mut processes, self.sort);
// Apply limit if specified
if let Some(limit) = self.limit {
processes.truncate(limit);
}
// Build context string for output
let mut context_parts = vec![format!("by '{}'", self.name)];
if let Some(ref dir) = in_dir_filter {
context_parts.push(format!("in {}", dir.display()));
}
let context = Some(context_parts.join(" "));
printer.print_processes_as("by", &processes, context.as_deref());
Ok(())
}
}