0

My inputs are commands followed by an unrestricted number of single-letter options, e.g. command -abc. Neither the command nor the options take any arguments. My goal is to remove certain options.

Removing options b and c as an example, I can achieve this like this:

$ cmd='command -abc'
$ pattern='(.*) -(.*)'
$ [[ $cmd =~ $pattern ]]
$ echo "${BASH_REMATCH[1]} -${BASH_REMATCH[2]//[cb]}"
command -a

However, this only works in bash. How can I solve this problem in a compatible way, e.g. using sed and grep ?

3
  • What is known about the command? Do you know all its options and what options takes arguments? Commented Oct 17, 2022 at 19:35
  • 1
    Another way to put it: In your example, command -abc, how do you know it isn't a single option -a with an option-argument bc (or -a -b c, i.e. -b takes an option-argument)? And what happens with command -abc -d -- -abc? With real command line parsing, removing -b and -c, that should probably become command -a -d -- -abc, assuming -a takes no argument, and regardless of whether -b takes an argument or not, right? If -a takes an argument, the command line options should remain unchanged, right? Commented Oct 17, 2022 at 20:06
  • @Kusalananda there are no arguments/option-arguments for the command, only single-letter options. In case there are no options the input is command --. Commented Oct 18, 2022 at 6:56

1 Answer 1

1

Assuming that the command only takes single letter options, and that none of the options takes an argument, we may create a wrapping script that parses the command line options, remove the unwanted options and executes the command given the new set of options:

#!/bin/sh

savedopts=-

printf 'Args in  = %s\n' "$*"

while getopts :bc opt; do
        case $opt in
                b|c) ;; # nothing
                *)
                        savedopts="$savedopts$OPTARG"
        esac
done

shift "$(( OPTIND - 1 ))"

set -- "$savedopts" -- "$@"

printf 'Args out = %s\n' "$*"

# Run the command:

some-command "$@"

This parses the command line, ignores the options b and c, and puts the rest of the options into $savedopts.

$savedopts is then used to run the wrapped command, together with any operands given on the original command line (separated with --).

We don't get any errors from getopts even though we ask it to parse options that it may not expect. This is due to the initial : in the first argument to getopts.

Test run:

$ ./script -abcd -b -c -- -bx -a foo bar
Args in  = -abcd -b -c -- -bx -a foo bar
Args out = -ad -- -bx -a foo bar
./script: some-command: not found
1
  • Thank you, this works very well! However, this seems overly complex for a simple problem. Except for when there are no options, the input always has exactly one -, followed by the letters. Is there no simple sed one-liner that behaves exactly like the code I put in my question? Commented Oct 18, 2022 at 10:52

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.