Reputation: 1263
I have a line which I have read from a file
line="1 \"Some Text Here\""
and a function which takes two arguments
print() {
echo $1
echo $2
}
When I execute
print $line
The output I get is
1
"Some
What I want to get is
1
Some Text Here
Upvotes: 2
Views: 7611
Reputation: 440297
If you trust the input, you can use eval
(normally to be avoided, as rogue input strings can do unwanted things):
line="1 \"Some Text Here\""
eval print "$line" # `print` is the shell function from the question
Even with harmless input strings, however, the eval
command will break if the input string contains so-called shell metacharacters: | & ; ( ) < >
.
Also, if the string happens to contain tokens such as *
that look like pathname patterns (globs), they would inadvertently get expanded; the relevant pattern characters are: * ? [ ]
.
Thus, to make the above more robust, escape pattern characters and metacharacters in the input string with \
as follows:
eval print "$(sed 's/[][*?&;()<>]/\\&/g' <<<"$line")"
Update: It turns out that there's no need for eval
, after all: the problem can be solved with xargs
, which recognizes quoted substrings inside a string literal.:
#!/usr/bin/env bash
# Sample function that prints each argument passed to it separately
print() {
for arg; do
echo "[$arg]" # enclose value in [] to better see its boundaries
done
}
# Sample input string with embedded quoted strings, an unqoted
# glob-like string, and an string containing shell metacharacters
line="1 \"double-quoted string\" * 'single-quoted string' string-with-;|>-(metachars)"
# Let `xargs` split the string into lines (-n 1) and read the
# result into a bash array (read -ra).
# This relies on `xargs`' ability to recognize quoted strings embedded
# in a string literal.
IFS=$'\n' read -d '' -ra args <<<"$(xargs -n 1 printf '%s\n' <<<"$line")"
# Now pass the array to the `print` function.
print "${args[@]}"
Result:
[1]
[double-quoted string]
[*]
[single-quoted string]
[string-with-;|>-(metachars)]
Notes and limitations:
Unquoted tokens allow use of \
to escape embedded characters such as spaces, single and double quotes.
\
before other characters is also ignored, which can be undesired; e.g.: echo 'a\b' | xargs # -> 'ab'
- either use \\
, or single- or double-quote the token instead.Quoted tokens do not require interior \
-escaping, but sadly, do not support embedding quotes of the same type - no escaping seems to work.
Note that specifying printf '%s\n'
as the command to execute by xargs
is typically not necessary, because xargs
defaults to invoking the echo
utility (not the shell builtin); however, some echo
implementations recognize options of their own, such as -e
(while not supporting --
), so that the first output token could be mistaken for an option.
By contrast, printf '%s\n
works in all situations.
Quoted strings that have embedded newlines are not supported. (xargs
reports a parsing error in that case) - presumably, this will rarely be a problem.
Upvotes: 5
Reputation: 20909
Depending on your specific situation, using shift
might work for you.
For example:
print() {
echo "$1"
shift
echo "$*"
}
This prints the first parameter, shift the parameter list (removing the first parameter), then prints the remaining parameters.
That should give you this result:
$ text="1 \"Multiple Words Here\""
$ print() {
> echo "$1"
> shift
> echo "$*"
> }
$ print $text
1
"Multiple Words Here"
Upvotes: 0
Reputation: 683
You need to use the variable IFS
. In your script type IFS=\"
. This should fix your problem .
Upvotes: 0