0

I want to list a process with its infos through ps in shell. Here is my script:

#!/bin/sh

for line in `ps aux| grep test.py`
do
    echo $line
done

But output is:

hey
13241
0.0
0.3
48388
13528
pts/18
S+
18:50
0:00
python
test.py
hey
13370
0.0
0.0
14504
1016
pts/21
S+
19:00
0:00
grep
test.py

It divide the line into many parts, but I want I can get one line information about the process which name is test.py like command in terminal:

hey   13241  0.0  0.3  48388 13528 pts/18   S+   18:50   0:00 python test.py
hey   13446  0.0  0.0  14504   976 pts/21   S+   19:08   0:00 grep --color=auto test.py

how to solve that

melpomene
  • 84,125
  • 8
  • 85
  • 148
code_worker
  • 384
  • 3
  • 16
  • 6
    http://mywiki.wooledge.org/DontReadLinesWithFor – melpomene Oct 06 '17 at 11:13
  • Nothing about this is specific to `ps` -- answers about how to iterate over input from other sources line-by-line are every bit as valid. – Charles Duffy Oct 06 '17 at 19:56
  • 1
    (That said, in general, you shouldn't be using output from `ps` in your scripts if you can avoid it. For most uses `pgrep` is more appropriate, or using an approach such as advisory locking that doesn't require reading the process table at all to check if a program is running). – Charles Duffy Oct 06 '17 at 19:59

2 Answers2

2

Based on melpomene's comment, this should work for you while keeping compatibility to sh.

#!/bin/sh
ps aux | grep test.py | while IFS= read -r line; do
    printf '%s\n' "$line"
done 
Matthias
  • 7,432
  • 6
  • 55
  • 88
1

The read command will read one line from standard input and place it into a variable for you. It'll exit with status 1 when it reaches the end of input, which you can use to end a while loop:

ps aux | grep test.py | while read line; do
  echo LINE:
  echo "$line"
  echo
done

If you want it to, read will split the input into separate variables using the internal field separator (IFS), and if the input has more fields than variables, it'll stop splitting when it gets to your last variable and just put the remainder of the line, unsplit, in there.

Which means that if you supply just one variable (I called it "line" in the example above), you'll get the whole line, unsplit, and you won't need to worry about setting IFS.

Rob Davis
  • 15,597
  • 5
  • 45
  • 49