3

I want to store options to arbitrary commands as strings in bash so that I can do e.g.

presets_A='-A'
presets_B='-A -l -F'
ls $presets_A
ls $presets_B

The first one works, the socond gives ls: invalid option -- ' '.

The same happens when I try to store the entire command in a string variable (as opposed to a function or an alias, which is not what I want):

presets_A='ls -A'
presets_B='ls -A -l -F'
$presets_A
$presets_B

This gives ls -A: command not found. Not good. Obviously, I haven't yet found the correct arbitrary mixture of $%"(@]}" quotes and parens that Bash is so famous for. ${!presets_A} also didn't work but chances are I got confused and messed up.

EDIT for clarification, I do know how to use a function to encapsulate setting options and subsuming a bunch of parametrized calls under a single command. What I'm looking for is the equivalent of (Bash) foo "$@" or (Python) foo( *P, **Q ) or JS foo( ...P ) such that I get a single serializable and transportable value that comprises the arguments to a call in a single place.

6
  • 2
    Obligatory link mywiki.wooledge.org/BashFAQ/050 - and it's not an arbitrary mixture of those symbols that you're looking for. Commented Mar 12, 2018 at 13:10
  • 2
    I'm unable to reproduce this with your code as posted. Are you sure you're not quoting the variables? Have you modified IFS? Commented Mar 12, 2018 at 13:39
  • @TomFenech I know but it occasionally does feel that way Commented Mar 12, 2018 at 13:47
  • 1
    as @thatotherguy said, there's nothing actually wrong with presets_B='-A -l -F' followed by ls $presets_B - could you expand on your question so that we can reproduce your issue? Commented Mar 12, 2018 at 14:27
  • Why don't you just use an alias like alias lB="ls -A -l -F" Commented Mar 13, 2018 at 12:08

2 Answers 2

4

If functions really don't do what you want, then you can use an array to separate the arguments:

presets_A=( -A )
presets_B=( "${presets_A[@]}" -l -F ) # or just -A -l -F

ls "${presets_A[@]}" # ls -A
ls "${presets_B[@]}" # ls -A -l -F

Use "${array[@]}" to expand the array into a list of arguments, separated by the field separator (a space, by default).

But I would consider just defining two functions

la () {
  ls -A
}

lalf () {
  ls -A -l -F
}
Sign up to request clarification or add additional context in comments.

1 Comment

Worked like a charm for my script to preload common database options, thanks!
0

I've since found the source for my troubles; I had tried to use a variable for options in a script with this header:

#!/usr/bin/env bash
set -euo pipefail; IFS=$'\n\t'

presets_A='-A'
presets_B='-A -l -F'
ls $presets_A
ls $presets_B

It does work as intended when I remove the Internal Field Separator setting, and I therefore think the correct answer to my question is:

"Storing multiple command arguments in a variable is OK in Bash and should work as long as IFS has not been reset to something other than a space."

I can affirm that

#!/usr/bin/env bash
set -euo pipefail; IFS=$' '

presets_A='-A'
presets_B='-A -l -F'
command_C='ls -A -l -F'
ls $presets_A
echo '----------------------------------'
ls $presets_B
echo '----------------------------------'
$command_C

does work as expected; thanks go to @TomFenech for pointing out that much (note the explicit IFS=' ' near the top).

FWIW the reason i had re-set IFS is that there are quite a few recommendations to do so out there; they call it 'Bash strict mode'. Turns out it makes your scripts incompatible in subtle ways.

Comments

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.