mirror of
https://github.com/uutils/procps.git
synced 2026-05-06 06:06:43 -04:00
ps: Implement --pid flag
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use clap::ArgMatches;
|
||||
use std::collections::HashSet;
|
||||
use uu_pgrep::process::{walk_process, ProcessInformation, RunState, Teletype};
|
||||
use uucore::error::UResult;
|
||||
|
||||
@@ -46,6 +47,9 @@ pub struct ProcessSelectionSettings {
|
||||
/// - '-x' Lift "must have a tty" restriction.
|
||||
pub dont_require_tty: bool,
|
||||
|
||||
/// Select specific process IDs (-p, --pid)
|
||||
pub pids: Option<HashSet<usize>>,
|
||||
|
||||
/// - `-r` Restrict the selection to only running processes.
|
||||
pub only_running: bool,
|
||||
|
||||
@@ -60,6 +64,9 @@ impl ProcessSelectionSettings {
|
||||
select_non_session_leaders_with_tty: matches.get_flag("a"),
|
||||
select_non_session_leaders: matches.get_flag("d"),
|
||||
dont_require_tty: matches.get_flag("x"),
|
||||
pids: matches
|
||||
.get_many::<Vec<usize>>("pid")
|
||||
.map(|xs| xs.flatten().copied().collect()),
|
||||
only_running: matches.get_flag("r"),
|
||||
negate_selection: matches.get_flag("deselect"),
|
||||
}
|
||||
@@ -75,6 +82,10 @@ impl ProcessSelectionSettings {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
if let Some(ref pids) = self.pids {
|
||||
return Ok(pids.contains(&process.pid));
|
||||
}
|
||||
|
||||
if self.select_all {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
+17
-1
@@ -138,6 +138,15 @@ fn collect_format(
|
||||
Ok(collect)
|
||||
}
|
||||
|
||||
fn parse_numeric_list(s: &str) -> Result<Vec<usize>, String> {
|
||||
s.split(|c: char| c.is_whitespace() || c == ',')
|
||||
.map(|word| {
|
||||
word.parse::<usize>()
|
||||
.map_err(|_| format!("invalid number: '{}'", word))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn uu_app() -> Command {
|
||||
Command::new(uucore::util_name())
|
||||
@@ -262,6 +271,14 @@ pub fn uu_app() -> Command {
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("do not print header at all"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("pid")
|
||||
.short('p')
|
||||
.long("pid")
|
||||
.action(ArgAction::Append)
|
||||
.value_parser(parse_numeric_list)
|
||||
.help("select by process ID"),
|
||||
)
|
||||
// .args([
|
||||
// Arg::new("command").short('c').help("command name"),
|
||||
// Arg::new("GID")
|
||||
@@ -272,7 +289,6 @@ pub fn uu_app() -> Command {
|
||||
// .short('g')
|
||||
// .long("group")
|
||||
// .help("session or effective group name"),
|
||||
// Arg::new("PID").short('p').long("pid").help("process id"),
|
||||
// Arg::new("pPID").long("ppid").help("parent process id"),
|
||||
// Arg::new("qPID")
|
||||
// .short('q')
|
||||
|
||||
@@ -202,3 +202,38 @@ fn test_deselect() {
|
||||
.succeeds()
|
||||
.stdout_matches(&Regex::new("\n *1 ").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_pid_selection() {
|
||||
let our_pid = std::process::id();
|
||||
// Test that only pid 1 and pid of the test runner is present
|
||||
let test = |pid_args: &[&str]| {
|
||||
let match_regex = Regex::new(&format!("^ *1 *\n *{our_pid} *\n$")).unwrap();
|
||||
let mut args = vec!["--no-headers", "-o", "pid"];
|
||||
args.extend_from_slice(pid_args);
|
||||
new_ucmd!()
|
||||
.args(&args)
|
||||
.succeeds()
|
||||
.stdout_matches(&match_regex);
|
||||
};
|
||||
|
||||
for flag in ["-p", "--pid"] {
|
||||
test(&[flag, &format!("1 {our_pid}")]);
|
||||
test(&[flag, &format!("1,{our_pid}")]);
|
||||
test(&[flag, "1", flag, &our_pid.to_string()]);
|
||||
}
|
||||
|
||||
// Test nonexistent PID (should show no output)
|
||||
new_ucmd!()
|
||||
.args(&["-p", "0", "--no-headers"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stdout_is("");
|
||||
|
||||
// Test invalid PID
|
||||
new_ucmd!()
|
||||
.args(&["-p", "invalid"])
|
||||
.fails()
|
||||
.stderr_contains("invalid number");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user