0

I have the following code snippet:

#!/bin/bash
clear
echo "PS to AWK"

read prg

check=($(ps -e | grep $prg | awk '{print "kILL " $4" "$1 " ? [y/n]"}'))

echo "${check[@]}"

The assumed output should be:

PS to AWK
auda
kILL audacious 2423 ? [y/n]

But unfortunately my output looks like this:

PS to AWK
auda
kILL audacious 2423 d i [y/n]

Someone has a hint why the question mark is lost and where the "d" and "i" are resulting from?

Thanks in advance for your answers.

John Goofy
  • 1,330
  • 1
  • 10
  • 20
  • Why are you populating array `check`? – anubhava Mar 26 '17 at 17:18
  • Because for later use. – John Goofy Mar 26 '17 at 17:21
  • @tripleee: Sorry I had to reopen this because that duplicate marked answer doesn't really answer this problem. – anubhava Mar 26 '17 at 17:28
  • There are different pitfalls If I quote or not, even if I use extra spaces or not. There right answer below solves my problem, the suggested answer does not. The big hint is `check < <(...)` and I can use my quotation without any problems, as I always do. I think it is more direction-related. – John Goofy Mar 26 '17 at 18:16
  • Why don't you use `pgrep auda` ? `tokill=$(pgrep $prg);cmdname=$(ps ho cmd $tokill);read -p "Kill: $cmdname: $tokill" ... ` – F. Hauri - Give Up GitHub Mar 27 '17 at 07:40

2 Answers2

2

Instead of populating your shell array check using output from command substitution (which is subjected to glob expansion and word spitting) you should use read with process substitution like this:

read -ra check < <(ps -e | awk -v p="$prg" '$0 ~ p{print "kILL " $4" "$1 " ? [y/n]"}')

Then examine the result using:

echo "${check[@]}"

# or
declare -p check
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 1
    anubhava: Thank you, this works perfect for me, and checking an array with `declare` is really very helpfull. – John Goofy Mar 26 '17 at 17:40
1

The unquoted ? is expanded as a wildcard by the shell. You have two files with single-character names in the current directory.

The fix is to generally quote everything, unless you specifically require the shell to perform wildcard expansion and whitespace tokenization on a value.

The wildcard gets expanded in the array assignment, so you could quote that:

check=("$(ps -e | awk -v prg="$prg" '$0 ~ prg {print "kILL " $4" "$1 " ? [y/n]"}')")

but then you might was well not use an array. But then you might as well just capture the PID.

pid=$(ps -e | awk -v prg="$prg" '$0 ~ prg { print $1 }')

This loses the process name, though. You could refactor the script to print just the machine-readable parts, and then use those in a print statement.

check=($(ps -e | awk -v prg="$prg" '$0 ~ prg { print $1, $4 }'))
read -p "kILL ${check[1]} ${check[0]}? [y/n]"

(Incidentally, aligning the question mark with the previous word, as is the convention in English orthography, would also fix your problem, though sort of accidentally. Notice also how to avoid the useless use of grep in the examples above.)

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • If I quote the question mark like this `check=($(ps -e | grep $prg | awk '{print "kILL " $4" "$1 " \? [y/n]"}'))` I only get an additional warning and there is still no `?`in my output. – John Goofy Mar 26 '17 at 17:18
  • Awk processes and removes the backslash so it's no longer there by the time the shell evaluates the output from Awk. I would just print the PID from Awk and defer the string formatting to the final `echo` (or perhaps `read -p` if you are going to be reading user input anyway). – tripleee Mar 26 '17 at 17:24