Linux How do I break up an extremely long string literal in bash?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7729023/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 06:37:29  来源:igfitidea点击:

How do I break up an extremely long string literal in bash?

linuxbash

提问by Simon Nickerson

I would like to embed a long command like this in a bash script:

I would like to embed a long command like this in a bash script:

mycommand \
    --server myserver \
    --filename extremely/long/file/name/that/i/would/like/to/be/able/to/break/up/if/possible \
    --otherflag \
    --anotherflag

with the long filename broken up.

with the long filename broken up.

I could do this:

I could do this:

# Insufficiently pretty
mycommand \
    --server myserver \
    --filename extremely/long/file/name/\
that/i/would/like/to/be/able/to/break/\
up/if/possible \
    --otherflag \
    --anotherflag \

but it breaks the flow. I would liketo be able to write this:

but it breaks the flow. I would liketo be able to write this:

# Doesn't work
mycommand \
    --server myserver \
    --filename extremely/long/file/name/\
         that/i/would/like/to/be/able/to/break/\
         up/if/possible \
    --otherflag \
    --anotherflag

but that doesn't work because it breaks up the string literal.

but that doesn't work because it breaks up the string literal.

Is there a way to tell bash to break a string literal but ignore any leading spaces?

Is there a way to tell bash to break a string literal but ignore any leading spaces?

采纳答案by WilQu

You can use a variable :

You can use a variable :

file=extremely/long/file/name
file+=/that/i/would/like/to/be/able/to/break
file+=/up/if/possible

mycommand\
    --server myserver\
    --filename $file\
    --flag flag

回答by Chriszuma

It's a bit of ahack, but this works:

It's a bit of ahack, but this works:

mycommand \
    --server myserver \
    --filename "extremely/long/file/name/"`
               `"that/i/would/like/to/be/able/to/break/"`
               `"up/if/possible" \
    --otherflag \
    --anotherflag

Bash concatenates string literals that are adjacent, so we take advantage of that. For example, echo "hi" "there"prints hi therewhereas echo "hi""there"prints hithere.

Bash concatenates string literals that are adjacent, so we take advantage of that. For example, echo "hi" "there"prints hi therewhereas echo "hi""there"prints hithere.

It also takes advantage of the backtick operator, and the fact that a bunch of spaces evaluates to nothing.

It also takes advantage of the backtick operator, and the fact that a bunch of spaces evaluates to nothing.

回答by Peter.O

Basically, there is nothing built into bash to do this.
A wrapper is typically more trouble than it's worth, but that said, you could try an alias or a funciton, eg. j

Basically, there is nothing built into bash to do this.
A wrapper is typically more trouble than it's worth, but that said, you could try an alias or a funciton, eg. j

j(){sed -e ':a;$!N;s/ *\n *//g;ta' <<<""}

echo "$(j "3   spaces  
           /hello
           /world
           /this
           /is
           /a
           /long
           /path
          ")"

# 3   spaces/hello/world/this/is/a/long/path

回答by Cookyt

I define a short strcat function at the top of my bash script and use an inline invocation to split things up. I sometimes prefer it to using a separate variable because I can define the long literal in-line with the command invocation.

I define a short strcat function at the top of my bash script and use an inline invocation to split things up. I sometimes prefer it to using a separate variable because I can define the long literal in-line with the command invocation.

function strcat() {
  local IFS=""
  echo -n "$*"
}

mycommand \
  --server myserver \
  --filename "$(strcat \
      extremely/long/file/name/ \
      that/i/would/like/to/be/able/to/break/ \
      up/if/possible)" \
  --otherflag \
  --anotherflag \

I also like this approach for when I have to enter a long CSV of values as a flag parameter because I can use it to avoid typing the comma between values:

I also like this approach for when I have to enter a long CSV of values as a flag parameter because I can use it to avoid typing the comma between values:

function strjoin() {
  local IFS=""
  shift
  echo -n "$*"
}

csv_args=(
  foo=hello
  bar=world
  "this=arg  has  spaces  in  it"
)
mycommand \
  --server myserver \
  --csv_args "$(strjoin , "${csv_args[@]}")" \
  --otherflag \
  --anotherflag \

Which is equivalent to

Which is equivalent to

mycommand \
  --server myserver \
  --csv_args "foo=hello,bar=world,this=arg  has  spaces  in  it" \
  --otherflag \
  --anotherflag \

回答by tworec

One can also use an array variable

One can also use an array variable

file=(extremely/long/file/name
    /that/i/would/like/to/be/able/to/break
    /up/if/possible)
IFS=''

echo mycommand\
    --server myserver\
    --filename "${file[*]}"\
    --flag flag

回答by Benjamin W.

Another way of writing a long string to a variable while keeping the maximum line length at bay:

Another way of writing a long string to a variable while keeping the maximum line length at bay:

printf -v fname '%s' \
    'extremely/long/file/name/that/i/' \
    'would/like/to/be/able/to/break/up/' \
    'if/possible'

Because there are more arguments than formatting directives, %sis just repeated and we get

Because there are more arguments than formatting directives, %sis just repeated and we get

$ declare -p fname
declare -- fname="extremely/long/file/name/that/i/would/like/to/be/able/to/break/up/if/possible"

which an be used like

which an be used like

mycommand \
    --server myserver \
    --filename "$fname" \
    --otherflag \
    --anotherflag

This is extra handy when setting long variables with inherently separated contents such as CDPATH(or PATH, of course):

This is extra handy when setting long variables with inherently separated contents such as CDPATH(or PATH, of course):

printf -v CDPATH '%s' \
    ':/Users/benjamin/here/is/a/long/path' \
    ':/Users/benjamin/and/here/is/another/one' \
    ':/Users/benjamin/and/a/third/line'
export CDPATH

as opposed to

as opposed to

export CDPATH=':/Users/benjamin/here/is/a/long/path:/Users/benjamin/and/here/is/another/one:/Users/benjamin/and/a/third/line'

or the clunky

or the clunky

export CDPATH=':/Users/benjamin/here/is/a/long/path'
CDPATH+=':/Users/benjamin/and/here/is/another/one'
CDPATH+=':/Users/benjamin/and/a/third/line'