251

I have a Github action command that is really long:

name: build

on: [push]

jobs:
    build:
        runs-on: ubuntu-18.04
        steps:
            - uses: actions/checkout@v1
            - name: Install Prerequisites
              run: |
                sudo apt-get update
                sudo apt-get install -y --no-install-recommends "a very very long list of prerequisites"

May I know whether it is possible to split the long command into multiple lines for better readability? I have tried the separator '' but it does not work.

7 Answers 7

299

I have a multi line command using backslash to separate the lines as follows:

- name: Configure functions
  run: |
    firebase functions:config:set \
      some.key1="${{ secrets.SOME_KEY_1 }}" \
      some.key2="${{ secrets.SOME_KEY_2 }}" \
    ...    

Note the preceding '|' character, and make sure the subsequent lines after the first one are indented (tabulated).

Sign up to request clarification or add additional context in comments.

21 Comments

This is the correct answer and would be a better accepted answer. The backslashes work the same as a multiline command in bash. (I'd recommend a hanging indent for readability though.)
I don't know how did it work previously for anyone, but adding a backslash does not work right now with GitHub Actions. This shouldn't be the accepted answer.
I confirm: this does not work on GitHub Actions as of now. You need to use ">" instead of "I" (see other answers)
Use ">". "|" doesn't work anymore.
It works for the moment. Make sure you have a whitespace before the backslash, too.
|
191

You can use the YAML folded style with > which is supported by GitHub Actions.

For example,

run: >
  xvfb-run
  ./mvnw -f my/pom.xml
  clean verify
  -DskipTests

newlines will be replaced with spaces so the above is equivalent to

run: xvfb-run ./mvnw -f my/pom.xml clean verify -DskipTests

8 Comments

Also see yaml-multiline.info to play around with the different scalar / chomping styles.
This works, thank you! Important note: per yml spec, white space is important here, so any extra tabs before the lines will cause problems.
It seems to work but it doesn't fail on any errors, same with | also.. so it becomes kind of pointless..
@JohnnyOshika Thank you for that comment! It cleared a long standing misunderstanding for me.
As @JohnnyOshika points out, white space is critical here (learned it the hard way). If a line starts with extra spaces, the line will be ignored. So make sure all lines start at the same column.
|
144

Going to share this in since it has not been mentioned.

You can use:

  • | called a Literal Block Scalar which preserves new lines and trailing spaces
  • > called a Folded Block Scalar which converts new lines into spaces
  • plain old strings, either unquoted, single-quoted or double-quoted

Additionally, you can append a block chomping indicator, -, + or none. which will alter the newlines at the end of the block.

these are the block chomping definitions

  • - is called strip removes newlines at the end
  • + is called keep keeps all newlines at the end
  • default behavior is keeping a single newline at the end

I found the site yaml-multiline.info useful for understanding how yaml strings are interpreted.

For my use case, I ended up doing the following:

run: >-
  for i in $(find . -type f -name "*.log");
  do
   echo "File: ${i} \n";
   cat $i;
   printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' -;
  done

7 Comments

What does the hyphen in >- do?
@silkfire According to the linked website, it appears to strip newlines from the end of the block, so that there's not an extra trailing \n at the end.
That said, this is not supported by GitHub Actions: github.com/actions/runner/issues/418
It's supported now.
@PaulRazvanBerg, as I mentioned in my earlier comment, adding the hyphen (i.e., >-) strips the last newline character, while not including it (i.e., >) includes a newline at the end of the string.
|
38

The above answers all had pieces, but this is what worked for me in a github composite action. It should work in a regular workflow too.

As @lorenzo-bettini said, if you want everything to be on one line, use what @Josue Alexander Ibarra called a Folded Block Scalar.

run: >
  xvfb-run
  ./mvnw -f my/pom.xml
  clean verify
  -DskipTests

newlines will be replaced with spaces so the above is equivalent to

run: xvfb-run ./mvnw -f my/pom.xml clean verify -DskipTests

Edit: @Connor Clark below suggests making sure that each line has the same indentation.

If you want new lines to be preserved, use what @Josue Alexander Ibarra called a Literal Block Scalar.

run: |
  FILE=./package.json
  if test -f "$FILE"
  then
    echo "$FILE exists."
  else
    echo "File does not exist"
  fi

When you do a multi-line run, though, you have to make sure you indent correctly, otherwise step will think that shell: bash is part of the run: | string.

WRONG:

  steps:
    - run: |
      FILE=./package.json
      if test -f "$FILE"
      then
        echo "$FILE exists."
      else
        echo "File does not exist"
      fi
      shell: bash

RIGHT:

  steps:
    - run: |
        FILE=./package.json
        if test -f "$FILE"
        then
          echo "$FILE exists."
        else
          echo "File does not exist"
        fi
      shell: bash

1 Comment

Important: for the '>' block, make sure each line has the same indentation.
12

At the time this answer was originally written, this was not possible using backslashes. See the accepted answer on how to do it now.


As far as I know, GitHub Actions does not support that.

However, you can use environment variables for that.

For example, this script splits your command in 3 lines of code and executes it as one line.

steps:
  - name: Install Prerequisites
    run: |
      sudo apt-get update
      bash -c "$line1 $line2 $line3"
    env:
    - line1='sudo apt-get install -y --no-install-recommends '
    - line2='a very very long list'
    - line3='of prerequisites'

It creates the environment variables line1, line2 and line3 and concats and executes them in a bash session.

1 Comment

$line1 $line2 $line3 directly works without requiring another bash
4

Note also the join and format functions for expressions:

HELLO_WORLD = ${{ join('Hello', 'world!') }}
HELLO_WORLD = ${{ format('{{Hello {0}}}', 'World') }}

Presumably these could be combined with env variables.

Comments

2

This is another way to do it, it will work with Github Actions:

name: build

on: [push]

jobs:
    build:
        runs-on: ubuntu-18.04
        steps:
            - name: Install Prerequisites
              uses: actions/checkout@v1
              run: >
                sudo apt-get update && 
                sudo apt-get install -y --no-install-recommends
                "a very very long 
                list of prerequisites"

alternative to the && is to split that in several steps, like:

name: build

on: [push]

jobs:
    build:
        runs-on: ubuntu-18.04
        steps:
            - name: Install Prerequisites - checkout phase
              uses: actions/checkout@v1

            - name: Install Prerequisites - update phase
              run: sudo apt-get update

            - name: Install Prerequisites - install phase
              run: >
                sudo apt-get install -y --no-install-recommends
                "a very very long
                list of prerequisites"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.