81

Given a command that takes a single long string argument like:

mycommand -arg1 "very long string which does not fit on the screen"

is it possible to somehow split it in a way similar to how separate arguments can be split with \.

I tried:

mycommand -arg1 "very \
long \
string \
which ..."

but this doesn't work.

mycommand is an external command so cannot be modified to take single arguments.

ccpizza
  • 28,968
  • 18
  • 162
  • 169
  • 2
    That should work, even without backslashes. Can you describe what do you mean by "it doesn't work"? – randomir Oct 18 '17 at 10:32
  • 1
    @randomir: the command does not accept the string as valid and throws an error while parsing it; (it's the keyword argument passed to `pytest -k "keyword1 or keyword2 or keyword3...`). **Updated**: you are right, I confirm the syntax in the original question works fine — turns out one keyword was starting with a number and that triggered an error in `pytest` (apparently a bug). – ccpizza Oct 18 '17 at 12:37
  • 1
    As long as the backslash is the last character of each line, that *almost* does what you want. You cannot indent the following lines, though, since those spaces will still be part of the string. – chepner Oct 18 '17 at 13:29
  • 1
    @randomir: Without the backslahes the string is multiline, which is not what the OP is willing for. – Jean Paul Aug 05 '20 at 10:30
  • And, you could also consider creating an intermediate variable to store it. – Константин Ван Jun 22 '21 at 19:59

3 Answers3

99

You can assign your string to a variable like this:

long_arg="my very long string\
 which does not fit\
 on the screen"

Then just use the variable:

mycommand "$long_arg"

Within double quotes, a newline preceded by a backslash is removed. Note that all the other white space in the string is significant, i.e. it will be present in the variable.

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
  • 1
    I suspect the OP didn't expect the indentation to be part of the resulting argument. (In which case `cat`+heredoc *could* help, using `<<-` and leading tabs, but that usually only provides indentation *close* to what you wanted.) – chepner Oct 18 '17 at 13:43
  • 2
    I have to do this ALL THE TIME in scripts that run anything with java, especially under oracle. I've had command strings so long that I broke the args up into groups, then assigned the groups in quoted supergoups so that the actual invocation was *logically* readable, and parseable if you read through all the setup. Painful, but sometimes necessary... – Paul Hodges Oct 18 '17 at 14:05
  • Thanks for this. I didn't think this would work with awk, but I used single quotes to set the variable to the script and then double quotes to refer to it, and, despite having double quotes in the awk script, it works! – nroose Oct 07 '19 at 17:08
  • 1
    Thanks. This technique also works with POSIX sh. – Anthony Geoghegan Apr 27 '21 at 19:25
  • This will have spaces before "which does not fit" – alper Aug 25 '22 at 12:12
  • @alper sure, it'll have any spaces on the first line up to the `\\` and any leading spaces from the second line. In the code in my answer, that would be one space. – Tom Fenech Aug 29 '22 at 14:03
9

Have you tried without the quotes?

$ foo() { echo -e "1-$1\n2-$2\n3-$3"; }

$ foo "1 \
2 \
3"

1-1 2 3
2-
3-

$ foo 1 \
2 \ 
3

1-1
2-2
3-3

When you encapsulate it in double-quotes, it's honoring your backslash and ignoring the following character, but since you're wrapping the whole thing in quotes, it's making it think that the entire block of text within the quotes should be treated as a single argument.

Eremite
  • 7,995
  • 2
  • 13
  • 6
0

I don’t want my strings to crawl along the left border. To keep the indentation, I do this.

join () {
    echo "$(IFS=; echo "$*")"
}

yourcommand\
    "$(
        join "your very long string"\
            " which does not fit"\
            " on the screen"
    )"

$* joins the arguments of the join function, with the IFS, that is temporarily set to be empty in a subshell, for the delimiter.