Stepan Loginov
Stepan Loginov

Reputation: 1767

Remove last word in bash variable

I have something like that:

...
args=$*
echo $args
...

result is

unusable1 unusable2 useful useful ... useful unusable3

I need remove all "unusable" args. They always at first, second and last position. After some investigation i find ${*:3} bash syntax. It help remove first two.

...
args=${*:3}
echo $args
...

result is

useful useful ... useful unusable3

But I can't find how to remove last word using same nice syntax.

Upvotes: 5

Views: 6916

Answers (6)

Charles Duffy
Charles Duffy

Reputation: 295989

args=${*:3} flattens your argument list. You don't want to do that. Consider following the pattern given below instead:

# this next line sets "$@" for testing purposes; you don't need it in real life
set -- \
  "first argument" \
  "second argument" \
  "third argument" \
  "fourth argument" \
  "fifth argument"

# trim the first two
args=( "${@:2}" )

# trim the last one
args=( "${args[@]:1:$(( ${#args[@]} - 2 ))}" )

# demonstrate the output content
printf '<%s>\n' "${args[@]}"

Running the above yields the following output:

<third argument>
<fourth argument>

...and, by doing so, demonstrates that it's correctly keeping arguments together, even when they contain spaces or wildcard characters.


For a shell completion script, you might also consider:

printf '%q ' "${args[@]}"

...which quotes content in such a way as to be eval'able by the shell.

Upvotes: 4

0x2b3bfa0
0x2b3bfa0

Reputation: 1065

Try with this:

args=$*

useful=${args#* }
useful=${useful#* }
useful=${useful% *}

Then you wlill get the interesting parameters in the $result variable.

Upvotes: -1

kranteg
kranteg

Reputation: 1001

Using your syntax, you can use this :

args=${*:3:$#-3}

Explanation :

${*:offset:length}

offset is 3 to begin to the third argument and length is the number of arguments minus 3 (two first and last one).

Upvotes: 3

chepner
chepner

Reputation: 532478

bash doesn't really provide such filtering methods for arrays. The best option is to just use a loop and filter one at a time.

for arg; do   # Implicitly iterate over $@
    [[ $arg =~ unusable ]] && continue
    args+=( "$arg" )
done

Upvotes: 0

anubhava
anubhava

Reputation: 786319

You can use a function/script like this to print all but last arguments:

func() {
   echo "${@:1:$#-1}";
}

func aa bb cc dd ee
aa bb cc dd

func foo bar baz hello how are you
foo bar baz hello how are

Upvotes: 6

hek2mgl
hek2mgl

Reputation: 158280

You could use awk:

args="unusable1 unusable2 useful useful ... useful unusable3"
args=$(awk '{$1=$2=$NF="";print}' <<< "$args")
echo "$args"

Output:

  useful useful ... useful 

The command sets the the first, second and the last ($NF) position to an empty string. NF holds the number of fields in awk. Therefore $NF is the last column.

Upvotes: 1

Related Questions