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

后端 未结 6 1111
独厮守ぢ
独厮守ぢ 2021-01-30 10:21

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/         


        
相关标签:
6条回答
  • 2021-01-30 10:54

    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
    
    0 讨论(0)
  • 2021-01-30 11:02

    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, %s is 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

    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):

    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

    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

    export CDPATH=':/Users/benjamin/here/is/a/long/path'
    CDPATH+=':/Users/benjamin/and/here/is/another/one'
    CDPATH+=':/Users/benjamin/and/a/third/line'
    
    0 讨论(0)
  • 2021-01-30 11:04

    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
    
    0 讨论(0)
  • 2021-01-30 11:17

    It's a bit of a hack, 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 there whereas echo "hi""there" prints hithere.

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

    0 讨论(0)
  • 2021-01-30 11:17

    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:

    function strjoin() {
      local IFS="$1"
      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

    mycommand \
      --server myserver \
      --csv_args "foo=hello,bar=world,this=arg  has  spaces  in  it" \
      --otherflag \
      --anotherflag \
    
    0 讨论(0)
  • 2021-01-30 11:17

    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' <<<"$1"}
    
    echo "$(j "3   spaces  
               /hello
               /world
               /this
               /is
               /a
               /long
               /path
              ")"
    
    # 3   spaces/hello/world/this/is/a/long/path
    
    0 讨论(0)
提交回复
热议问题