2

In an bash shell script I am receiving a list of argument in $@ which are : a b c d a c e Depending of the argument I need to do something specific with a case structure. But I only want to do it for a b c d e

I should only use bash and not any other language...I can use awk for example

for argument in "$@"
do
    case $argument in
a)
.....

Have tried many things but without success

Any help much appreciated

1
  • 2
    BTW, it's always better to show a specific thing you tried instead of just saying "many things". (Maybe show one, and describe a few of the others briefly -- knowing what you tried gives us a lot of context to use in building better answers). Commented Apr 21, 2021 at 21:08

2 Answers 2

5

Use an associative array to track arguments you've already seen. Note that this requires bash 4.0 or later; the 3.2.x release that Apple ships is too old, as it only supports numerically-indexed arrays (declare -a, but not declare -A).

#!/usr/bin/env bash
case $BASH_VERSION in ''|[0-3].*) echo "ERROR: Bash 4.0+ required" >&2; exit 1;; esac

declare -A seen=( )
declare -a deduped=( )

for arg in "$@"; do                # iterate over our argument list
  [[ ${seen[$arg]} ]] && continue  # already seen this? skip it
  seen[$arg]=1                     # mark as seen going forward...
  deduped+=( "$arg" )              # ...and add to our new/future argv
done

set -- "${deduped[@]}"  # replace "$@" with contents of deduped array
Sign up to request clarification or add additional context in comments.

1 Comment

If you are not concerned about the order in which the args are seen, instead of using a separate array deduped, you can set argv from the keys of seen with set -- "${!seen[@]}".
1

You could print, then sort unique, then print quoted the list and re-eval into arguments. With GNU tools:

set -- a b c d a c e
tmp=$(printf "%s\0" "$@" | sort -uz | xargs -0 printf "%q ")
eval set -- "$tmp"

3 Comments

If xargs calls /usr/bin/printf, it isn't guaranteed to support %q; that's specific to the shell-builtin printf in bash and ksh (unless it's a recent coreutils addition and I haven't been keeping up, but even then that would be GNU-centric).
...to be clear, I don't think this is a bad approach in general; if you did arr=( ); while IFS= read -r -d '' item; do arr+=( "$item" ); done < <(printf '%s\0' "$@" | sort -uz); set -- "${arr[@]}", that should work.
(Also as a rule, I always recommend eval "set -- $tmp" over eval set -- "$tmp" just for the sake of being more clear to the code's readers about how eval works, even though they're functionally identical in present circumstances).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.