0

Desired code:

echo "$var" | sort -t/ -k 1,1n -k2,2n -k3,3n  

Case scenario: options to sort arr dynamically created based on condition and stored in variables. How can i pass them.

option='-k 1,1n -k2,2n'
echo "$var" | sort -t/ "$option"

OR

echo "$var" | sort -t/ "$(eval echo "$option")

But nothing working. Throws stray character error

sort: stray character in field spec: invalid field specification ‘ 1,1n -k 2,2n -k 3,3n’
  • 1
    For single options with no args, use a variable (and double-quote it). For multiple options or options with args, use an array (and, again, double-quote it). Unquoted variables are a problem waiting to happen. Careless use of eval (i.e. without understanding and mitigating the risks) is even worse. – cas Jan 02 '22 at 13:29

2 Answers2

2

The following is a general answer that applies to your question specifically and any other situation where you may want to store command line arguments in a variable before actually using them.

The issue with your code is that when you use "$option" on the command line of sort, it is a single argument. You could, in this case, solve this by simply removing the quotes and letting the shell split the $option string on spaces, tabs, and newlines, and then perform filename globbing on those generated words before calling sort with the resulting list. Doing so would work in your case but would be a less elegant way of solving the issue.

It would be less elegant since it relies on the string $option to be correctly split on white spaces and not contain filename globbing patterns.

For a more generic solution, put the options and option-arguments in an array; that way, you may quote each argument that needs it. The following code assumes that you are using a shell, such as bash, which supports arrays.

options=( -k 1,1n -k 2,2n -k 3,3n )

sort -t '/' "${options[@]}" <<<"$var"

By quoting the expansion of ${options[@]}, you ensure that each element of the array options is expanded as a single field, which means that the shell would expand the options array as if all elements were given on the command line individually quoted as arguments to sort.

In shells without arrays, use the list of positional parameters instead:

set -- -k 1,1n -k 2,2n -k 3,3n

printf '%s\n' "$var" | sort -t '/' "$@"

Like with the first code snipped, the quoting of $@ is essential as it guarantees that each element of the list of positional parameters is expanded intact. The shell would, here too, expand "$@" into a list of fields and provide these as arguments to the sort utility.

In any case, you will want to avoid using echo to output the value of $var as echo my modify the data depending on the shell's configuration and the contents of the variable.

See also:

ilkkachu
  • 138,973
Kusalananda
  • 333,661
0

Note that the sort command needs to receive the options as separate parameter strings, i.e. sort -t/ -k 1,1n -k2,2n -k3,3n.

When you use a double-quoted expansion, like "$option", all the options will be passed as a single string, i.e. sort -t/ -k 1,1n -k2,2n -k3,3n.

To avoid that, just don't use quotes around $option:

option='-k 1,1n -k2,2n'
echo "$var" | sort -t/ $option

The -k option to sort can accept the field specification either as part of the same parameter string (-k2,2n) or as the next parameter string following the -k option (-k 1,1n). It can even accept spaces if the field specification is part of the same parameter string as the option specifier:

echo works | sort -t/ "-k 1,1n" -k2,2n -k3,3n
works

But even a single whitespace character in the same parameter string after the field specification is not acceptable:

echo fails | sort -t/ "-k 1,1n " -k2,2n -k3,3n
sort: stray character in field spec: invalid field specification ‘ 1,1n ’
telcoM
  • 96,466