wiki.bash-hackers.org/syntax/ccmd/classic_for.markup

152 lines
4.6 KiB
Plaintext
Raw Normal View History

2023-04-15 13:23:49 +02:00
====== The classic for-loop ======
===== Synopsis =====
2023-04-15 13:53:05 +02:00
<code>
for <NAME>; do
<LIST>
2023-04-15 13:23:49 +02:00
done
2023-04-15 13:53:05 +02:00
</code>
2023-04-15 13:23:49 +02:00
2023-04-15 13:53:05 +02:00
<code>
for <NAME> in <WORDS>; do
<LIST>
2023-04-15 13:23:49 +02:00
done
2023-04-15 13:53:05 +02:00
</code>
2023-04-15 13:23:49 +02:00
alternative, historical and undocumented syntax ((http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html#tag_23_02_09_12))
2023-04-15 13:53:05 +02:00
<code>
for <NAME>; {
<LIST>
2023-04-15 13:23:49 +02:00
}
2023-04-15 13:53:05 +02:00
for <NAME> in <WORDS>; {
<LIST>
2023-04-15 13:23:49 +02:00
}
2023-04-15 13:53:05 +02:00
</code>
2023-04-15 13:23:49 +02:00
===== Description =====
2023-04-15 13:53:05 +02:00
For every word in ''<WORDS>'', one iteration of the loop is performed and the variable ''<NAME>'' is set to the current word. If no &quot;''in <WORDS>''&quot; is present to give an own word-list, then the positional parameters (''&quot;$@&quot;'') are used (the arguments to the script or function). In this case (and only in this case), the semicolon between the variable name and the ''do'' is optional.
2023-04-15 13:23:49 +02:00
If you use the loop-variable inside the for-loop and it can contain spaces, you need to quote it, since normal word-splitting procedures apply.
:!: Like all loops (both ''for''-loops, ''while'' and ''until''), this loop can be
* terminated (broken) by the ''break'' command, optionally as ''break N'' to break ''N'' levels of nested loops
* forced to immediately do the next iteration using the ''continue'' command, optionally as ''continue N'' analog to ''break N''
2023-04-15 13:53:05 +02:00
Bash knows an alternative syntax for the ''for'' loop, enclosing the loop body in ''{<nowiki>...</nowiki>}'' instead of ''do <nowiki>...</nowiki> done'':
<code bash>
2023-04-15 13:23:49 +02:00
for x in 1 2 3
{
echo $x
}
2023-04-15 13:53:05 +02:00
</code>
2023-04-15 13:23:49 +02:00
This syntax is **not documented** and should not be used. I found the parser definitions for it in 1.x code, and in modern 4.x code. My guess is that it's there for compatiblity reasons. This syntax is not specified by POSIX(r).
==== Return status ====
2023-04-15 13:53:05 +02:00
The return status is the one of the last command executed in ''<LIST>'' or ''0'' (''TRUE''), if the item list ''<WORDS>'' evaluates to nothing (i.e.: &quot;is empty&quot;!).
2023-04-15 13:23:49 +02:00
===== Examples =====
==== Iterate over array elements ====
With some array syntax (see [[syntax:arrays]]) you can easily &quot;feed&quot; the for-loop to iterate over all elements in an array (by mass-expanding all elements):
2023-04-15 13:53:05 +02:00
<code bash>
2023-04-15 13:23:49 +02:00
for element in &quot;${myarray[@]}&quot;; do
echo &quot;Element: $element&quot;
done
2023-04-15 13:53:05 +02:00
</code>
2023-04-15 13:23:49 +02:00
Another way is to mass-expand all used indexes and access the array by index:
2023-04-15 13:53:05 +02:00
<code bash>
2023-04-15 13:23:49 +02:00
for index in &quot;${!myarray[@]}&quot;; do
echo &quot;Element[$index]: ${myarray[$index]}&quot;
done
2023-04-15 13:53:05 +02:00
</code>
2023-04-15 13:23:49 +02:00
==== List positional parameters ====
You can use this [[syntax:basicgrammar#shell_function_definitions | function]] to test how arguments to a command will be interpreted and parsed, and finally used:
2023-04-15 13:53:05 +02:00
<code bash>
2023-04-15 13:23:49 +02:00
argtest() {
n=1
for arg; do
echo &quot;Argument $((n++)): \&quot;$arg\&quot;&quot;
done
}
2023-04-15 13:53:05 +02:00
</code>
2023-04-15 13:23:49 +02:00
==== Loop through a directory ====
Since pathname expansion will expand all filenames to separate words, regardless of spaces, you can use the for-loop to iterate through filenames in a directory:
2023-04-15 13:53:05 +02:00
<code bash>
2023-04-15 13:23:49 +02:00
for fn in *; do
if [ -h &quot;$fn&quot; ]; then
echo -n &quot;Symlink: &quot;
elif [ -d &quot;$fn&quot; ]; then
echo -n &quot;Dir: &quot;
elif [ -f &quot;$fn&quot; ]; then
echo -n &quot;File: &quot;
else
echo -n &quot;Unknown: &quot;
fi
echo &quot;$fn&quot;
done
2023-04-15 13:53:05 +02:00
</code>
2023-04-15 13:23:49 +02:00
Stupid example, I know ;-)
==== Loop over lines of output ====
To be complete: You can change the internal field separator (IFS) to a newline and thus make a for-loop iterating over lines instead of words:
2023-04-15 13:53:05 +02:00
<code bash>
2023-04-15 13:23:49 +02:00
IFS=$'\n'
for f in $(ls); do
echo $f
done
2023-04-15 13:53:05 +02:00
</code>
2023-04-15 13:23:49 +02:00
This is just an example. In //general//
* it's not a good idea to parse ''ls(1)'' output
* the [[syntax:ccmd:while_loop|while loop]] (using the ''read'' command) is a better joice to iterate over lines
==== Nested for-loops ====
2023-04-15 13:53:05 +02:00
It's of course possible to use another for-loop as ''<LIST>''. Here, counting from 0 to 99 in a weird way:
2023-04-15 13:23:49 +02:00
2023-04-15 13:53:05 +02:00
<code bash>
2023-04-15 13:23:49 +02:00
for x in 0 1 2 3 4 5 6 7 8 9; do
for y in 0 1 2 3 4 5 6 7 8 9; do
echo $x$y
done
done
2023-04-15 13:53:05 +02:00
</code>
2023-04-15 13:23:49 +02:00
==== Loop over a number range ====
Beginning in Bash 4, you can also use &quot;sequence expression&quot; form of [[syntax:expansion:brace|brace expansion]] syntax when looping over numbers, and this form does not create leading zeroes unless you ask for them:
2023-04-15 13:53:05 +02:00
<code bash>
2023-04-15 13:23:49 +02:00
# 100 numbers, no leading zeroes
for x in {0..99}; do
echo $x
done
2023-04-15 13:53:05 +02:00
</code>
2023-04-15 13:23:49 +02:00
2023-04-15 13:53:05 +02:00
<code bash>
2023-04-15 13:23:49 +02:00
# Every other number, width 3
for x in {000..99..2}; do
echo $x
done
2023-04-15 13:53:05 +02:00
</code>
2023-04-15 13:23:49 +02:00
WARNING: the entire list is created before looping starts. If your list is huge this may be an issue, but no more so than for a glob that expands to a huge list.
===== Portability considerations =====
===== See also =====