This how I suggest you should do it, and I will explain why, but first I want to talk about something else...
set -- 'Arg 1: Line 1.' \
'Arg 2: Line 2.' \
'and so on for' \
'as long as you might like.'
var="$*"
A lot of the other proffered solutions here seem to suggest that you can somehow affect a shell variable's contents by altering your methods of expanding it. I can assure you this is not the case.
string="some stuff here \
some more stuff here."
echo $string ${#string}
echo "$string" "${#string}"
OUTPUT
some stuff here some more stuff here. 53
some stuff here some more stuff here. 53
What you see above is first a field-split expansion, then a report on the byte-count for the expansion's source variable, then a quote-delimited expansion, and the same byte-count. While the output may differ the contents of the shell variable $string
never changes at all except upon assignment.
What's more, if you do not understand why this is, you're bound to encounter some very nasty surprises sooner than later. Let's try that again, but in slightly different conditions.
IFS=sf
echo $string ${#string}
echo "$string" "${#string}"
Same $string
- different environment.
OUTPUT
ome tu here ome more tu here. 53
some stuff here some more stuff here. 53
Field splitting occurs based on the field delimiters defined in $IFS
. There are two kinds of delimiters - $IFS
whitespace and $IFS
anything else. By default $IFS
is assigned the value space tab newline - which are the three possible $IFS
whitespace values. It is easily changed, though, as you can see above, and can have drastic effects on field-split expansions.
$IFS
whitespace will elide by sequence to a single field - and this is why echo
ing an expansion containing any sequence of spaces when $IFS
contains a space will evaluate to only a single space - because echo
concatenates its arguments on spaces. But any non-whitespace values will not elide in the same way, and each occurring delimiter always gets a field unto itself - as can be seen in the stuff expansion above.
This is not the worst of it. Consider this other $string
.
IFS=$space$tab$newline
cd emptydir
string=" * * * \
* * * "
echo $string ${#string}
echo "$string" "${#string}"
OUTPUT
* * * * * * 30
* * * * * * 30
Looks ok, right? Well, let's alter the environment again.
touch file1 file2 file3 file4 file5
echo $string ${#string}
echo "$string" "${#string}"
OUTPUT
file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 30
* * * * * * 30
Woah.
By default the shell will expand filename globs if it can match them. This occurs after parameter expansion and field-splitting in its parse-order and so any unquoted string is vulnerable in this way. You can toggle this behavior off with set -f
if you like, but any POSIX-compatible shell will always glob by default.
This is the kind of stuff you're up against when you drop quotes on expansions to suit your indentation preferences. And even so, in every case, regardless of its expansion behavior, the actual value for $string
is always still whatever it was when you last assigned it. So let's get back to the first thing.
set -- 'Arg 1: Line 1.' \
'Arg 2: Line 2.' \
'and so on for' \
'as long as you might like.'
var="$*"
echo "$var" "${#var}"
OUTPUT
Arg 1: Line 1. Arg 2: Line 2. and so on for as long as you might like. 70
I believe this is a far saner way to adapt shell syntax to your indentation preferences. What I'm doing above is assigning each individual string to a positional parameter - which can each be referenced by number like $1
or ${33}
- and then assigning their concatenated values to $var
using the special shell parameter $*
.
This approach is not immune to $IFS
, even so. Still, I consider its relationship to $IFS
an added benefit in this respect. Consider:
IFS=\ ;space_split="$*"
IFS=/; slash_split="$*";IFS='
';new_line_split="$*"
echo "$space_split"
echo "$slash_split"
echo "$new_line_split"
OUTPUT
Arg 1: Line 1. Arg 2: Line 2. and so on for as long as you might like.
Arg 1: Line 1./Arg 2: Line 2./and so on for/as long as you might like.
Arg 1: Line 1.
Arg 2: Line 2.
and so on for
as long as you might like.
As you can see, $*
concatenates each arg in "$@"
on the first byte in $IFS
. So saving its value while $IFS
is differently assigned gets different field delimiters for each saved value. What you see above is the literal value for each variable, by the way. If you wanted no delimiter at all you would do:
IFS=;delimitless="$*"
echo "$delimitless" "${#delimitless}"
OUTPUT
Arg 1: Line 1.Arg 2: Line 2.and so on foras long as you might like. 67
$IFS
is a powerful and universal tool - but code written in this way can never produce reliable results of any kind. – mikeserv Oct 25 '14 at 11:32*
?
[]
). – mr.spuratic Oct 27 '14 at 11:09