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
|
From 5443c819622495fcdc759d5dd4e5c31633eab389 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ville=20Skytt=C3=A4?= <ville.skytta@iki.fi>
Date: Thu, 2 May 2019 16:57:25 +0300
Subject: [PATCH] _pnames: adapt for busybox ps, rewrite in pure bash
Closes https://github.com/scop/bash-completion/issues/318
---
bash_completion | 51 ++++++++++++++++++++++++++++++------------
test/t/test_killall.py | 4 ++++
2 files changed, 41 insertions(+), 14 deletions(-)
diff --git a/bash_completion b/bash_completion
index 58987a7fc1..bf7d02c753 100644
--- a/bash_completion
+++ b/bash_completion
@@ -1069,23 +1069,46 @@ _pnames()
} ||
_pnames()
{
+ local -a procs
if [[ "$1" == -s ]]; then
- COMPREPLY=( $(compgen -X '<defunct>' \
- -W '$(command ps axo comm | command sed -e 1d)' -- "$cur") )
+ procs=( $(command ps axo comm | command sed -e 1d) )
else
- # FIXME: completes "[kblockd/0]" to "0". Previously it was completed
- # to "kblockd" which isn't correct either. "kblockd/0" would be
- # arguably most correct, but killall from psmisc 22 treats arguments
- # containing "/" specially unless -r is given so that wouldn't quite
- # work either. Perhaps it'd be best to not complete these to anything
- # for now.
- COMPREPLY=( $(compgen -X '<defunct>' -W '$(command ps axo command= | command sed -e \
- "s/ .*//" -e \
- "s:.*/::" -e \
- "s/:$//" -e \
- "s/^[[(-]//" -e \
- "s/[])]$//" | sort -u)' -- "$cur") )
+ local line i=-1 OIFS=$IFS
+ IFS=$'\n'
+ local -a psout=( $(command ps axo command=) )
+ IFS=$OIFS
+ for line in "${psout[@]}"; do
+ if [[ $i -eq -1 ]]; then
+ # First line, see if it has COMMAND column header. For example
+ # the busybox ps does that, i.e. doesn't respect axo command=
+ if [[ $line =~ ^(.*[[:space:]])COMMAND([[:space:]]|$) ]]; then
+ # It does; store its index.
+ i=${#BASH_REMATCH[1]}
+ else
+ # Nope, fall through to "regular axo command=" parsing.
+ break
+ fi
+ else
+ #
+ line=${line:$i} # take command starting from found index
+ line=${line%% *} # trim arguments
+ procs+=( $line )
+ fi
+ done
+ if [[ $i -eq -1 ]]; then
+ # Regular axo command= parsing
+ for line in "${psout[@]}"; do
+ if [[ $line =~ ^[[(](.+)[])]$ ]]; then
+ procs+=( ${BASH_REMATCH[1]} )
+ else
+ line=${line%% *} # trim arguments
+ line=${line##@(*/|-)} # trim leading path and -
+ procs+=( $line )
+ fi
+ done
+ fi
fi
+ COMPREPLY=( $(compgen -X "<defunct>" -W '${procs[@]}' -- "$cur" ) )
}
# This function completes on user IDs
diff --git a/test/t/test_killall.py b/test/t/test_killall.py
index 725a16e4d6..136eee7373 100644
--- a/test/t/test_killall.py
+++ b/test/t/test_killall.py
@@ -11,3 +11,7 @@ def test_1(self, completion):
@pytest.mark.complete("killall --signal ")
def test_2(self, completion):
assert all(x in completion for x in "INT KILL TERM".split())
+
+ @pytest.mark.complete("killall ")
+ def test_3(self, completion):
+ assert "command=" not in completion
|