66

Is it possible to format this sample:

for i in string1 string2 stringN
do
 echo $i
done

to something similar to this:

for i in 
string1
string2
stringN
do
 echo $i
done

EDIT: Sorry for confusion, didn't realize that there was different methods of executing script - sh <scriptname> versus bash <scriptname> and also this thing which I cannot name right now - #!/bin/sh and #!/bin/bash :)

1

8 Answers 8

112

Using arrays in bash can aid readability: this array syntax allows arbitrary whitespace between words.

strings=(
    string1
    string2
    "string with spaces"
    stringN
)
for i in "${strings[@]}"; do
    echo "$i"
done
6
  • 2
    This seems most elegant, but unfortunately gives error: Syntax error: "(" unexpected Commented Jun 20, 2018 at 18:38
  • 2
    @waayee, then you're not running it in Bash. Remember that sh isn't necessarily Bash, and especially isn't on Debian and Ubuntu. Commented Jun 20, 2018 at 18:44
  • 1
    @ilkkachu Think I get it now - must run "bash <scriptname>" not "sh <scriptname>" :) Commented Jun 20, 2018 at 19:08
  • @waayee, or put a proper hashbang/shebang line and run it like an executable. Required reading: Does the shebang determine the shell which runs the script? Commented Jun 20, 2018 at 19:17
  • 2
    @rrrrr, your questions are probably answered here: stackoverflow.com/q/12314451/7552 Commented Nov 17, 2018 at 1:01
10

You can escape the linebreak with a backslash:

$ for i in \
> hello \
> world
> do
> echo $i
> done
hello
world
$
8
list='a b c d'
for element in $list;do 
    echo "$element"
done
2
  • You are missing semicolons! Commented Jul 23, 2019 at 8:46
  • Note that this would work as long as each string is a separate word. As soon as you have spaces in your strings, the spaces would break the string apart into multiple words. Also, if the $list string contains filename globbing characters (list='* * * *'), the shell would potentially replace these with matching filenames. Commented Jul 23, 2019 at 9:29
4

You may escape the newlines before/after each item that you loop over:

for i in \
    string1 \
    string2 \
    stringN
do
   printf '%s\n' "$i"
done

Or, for this simple example:

printf '%s\n' string1 string2 stringN

which has the same result.

Related:

Variation using a bash array:

strings=(
    string1
    string2
    stringN
)

printf '%s\n' "${strings[@]}"
0
2

If switching to zsh is an option:

for string (
  string1
  'other string'
  etc..
) printf '%s\n' "$string"
1

Same thing, less text:

array=(
        string{1..7}
)

for i in "${array[@]}"; do
    echo "$i"
done
2
  • string1 etc. aren’t the literal values to be displayed, they’re placeholders, so this approach doesn’t work. Commented Jan 28, 2020 at 12:59
  • if so, why bothering array ( … )? just do for i in string{1..7}; do echo "$i"; done; even printf '%s\n' string{1..7} Commented Jan 28, 2020 at 13:12
1

You can loop over a list of strings (with and without embedded spaces) as follows:

#!/usr/bin/env bash

var1="text-without-spaces"
var2="text with spaces"

for item in "${var1}" "${var2}" "more-without-spaces" "more with spaces"; do
    echo "'${item}'"
done

NB You can leave out braces around variable identifiers in the above example e.g. use $var1 instead of ${var1}.

This outputs:

'text-without-spaces'
'text with spaces'
'more-without-spaces'
'more with spaces'

0

You can use the loop command, available here, like so:

$ loop 'echo "$ITEM"' --for string1,string2,string3

or, if you have the list in a file, one per line:

$ <file_list.txt loop 'echo "$ITEM"'

Beware however that it runs one sh invocation per item (to interpret that code whilst the item is stored in the ITEM environment variable), and that it currently chokes on sequences of bytes that don't form valid characters in UTF-8 (even if the locale's charmap is not UTF-8).

You must log in to answer this question.