6

Suppose I have a graphical program named app. Usage example: app -t 'first tab' -t 'second tab' opens two 'tabs' in that program.

The question is: how can I execute the command (i.e. app) from within a bash script if the number of arguments can vary?

Consider this:

#!/bin/bash
tabs=(
    'first tab'
    'second tab'
)

# Open the app (starting with some tabs).
app  # ... How to get `app -t 'first tab' -t 'second tab'`?

I would like the above script to have an effect equivalent to app -t 'first tab' -t 'second tab'. How can such a bash script be written?

Edit: note that the question is asking about composing command line arguments on the fly using an array of arguments.

8

Giving the arguments from an array is easy, "${array[@]}" expands to the array entries as distinct words (arguments). We just need to add the -t flags. To do that, we can loop over the first array, and build another array for the full list of arguments, adding the -t flags as we go:

#!/bin/bash
tabs=("first tab" "second tab")
args=()
for t in "${tabs[@]}" ; do 
    args+=(-t "$t")
done
app "${args[@]}"

Use "$@" instead of "${tabs[@]}" to take the command line arguments of the script instead of a hard coded list.

| improve this answer | |
  • This won't quote args that have spaces. It's not the same. – ygoe Oct 24 '19 at 20:27
  • @ygoe, I'm not sure what you're comparing against. Quoting really only means anything when a shell command line is first processed. After that, it's better to think of shell "words" or the arguments that go to the command the shell runs (shell "words" can contain whitespace, so it's a somewhat confusing term). The array expansion like "${args[@]}" expands each element of the array to a separate word/argument, so the above works like app -t "first tab" -t "second tab". If there's some corner case where it fails, please do tell. – ilkkachu Oct 24 '19 at 20:54
4
tabs=("-t" "one tab" "-t" "second tab")
echo app "${tabs[@]}"
app -t one tab -t second tab

So now you should convert your original array to array with "-t" flags. Hope it's not a problem at all.

| improve this answer | |
0

It's easier with zsh:

#!/bin/zsh -
tabs=(
    'first tab'
    'second tab'
)

app -t$^tabs

That calls app as if you had entered:

app -t'first tab' -t'second tab'

rc, es and fish do that implicitly (zsh's $^array is actually inspired from rc's ^):

In those shells,

app -t$tabs

would do that as well.

To call app as if with

app -t 'first tab' -t 'second tab'

as opposed to

app -t'first tab' -t'second tab'

That is where -t and first tab are two different arguments to app, with zsh:

app ${${:--t}:^^tabs}

using the ${array1:^^array2} array-zipping operator where ${:--t} (minimal form of ${var:-default}) is used to inline the first array.

| improve this answer | |
-1

Basically the following bash script will read the file which include sites line by line and open each site in a new tab.

#!/bin/bash
while read line
do 
    xdg-open "$line"
done < /root/file

Usage

./script.sh sites

| improve this answer | |
  • Ah but you are running the command (xdg-open in your case) multiple times. I would like the command to be run only once. – Flux Dec 23 '17 at 8:44
  • The question is about getting the arguments from an array, not a file. – Barmar Dec 23 '17 at 11:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.