for i in $(seq 1 5); do echo $i; done
for i in {1..5}; do echo $i; done
for ((i=1; i<=5; i++)); do echo $i; done
start=37; stop=73; increment=7; for i in $(eval echo "{$start..$stop..$increment}"); do echo $i; done
(source)start=37; stop=73; increment=7; for((i=$start; i<$stop; i+=$increment)); do echo $i; done
start=0001; stop=1001; increment=100; for i in $(eval "echo {$start..$stop..$increment}"); do echo $i; done
++
at every loop :for ((i=1; i<1000000000000000000; i=i*10)); do echo "$i" | sed -r ': repeat s/([0-9]+)([0-9]{3})(,|$)/\1,\2/; t repeat' done
SPACE
sa b 'c d'
a b c d
temp files are BAAAD!, but readability matters
FileBaseName='file with spaces '; tmpDir=$(mktemp -d); touch "$tmpDir/$FileBaseName"{1,2,3} # doesn't work : for is puzzled by SPACEs for someFile in $(find "$tmpDir" -type f); do echo "$someFile"; done # works while read someFile; do echo "$someFile"; done < <(find "$tmpDir" -type f) # clean before leaving [ -d "$tmpDir" ] && rm -r "$tmpDir"
for
vs while
(source) :for line in $(cat file.txt); do echo $line; done
cat file.txt | while read line; do echo $line; done
while read line; do echo $line; done < file.txt
(more)
|
, or with $(...)
, or start the external cat command.#!/usr/bin/env bash doSomething() { random=$RANDOM echo "I'm working with '$1' and '$2' and '$3' (RANDOM = $random)" echo [ $random -lt 10000 ] && return 0 || return 1 faking failure } doSomethingUntilSuccess() { loopNumber=$((loopNumber+1)) echo "Doing 'doSomethingUntilSuccess' (loop $loopNumber) ..." doSomething 'foo' 'bar' 42 || doSomethingUntilSuccess } loopNumber=0 doSomethingUntilSuccess echo 'DONE !'
#!/usr/bin/env bash generateOneWord() { local length=$1 pwgen -0 $length 1 } generateWordsUntilMatchRegex() { local regex=$1 echo -n '.' generateOneWord "$wordLength" | grep -Ei "$regex" || generateWordsUntilMatchRegex "$regex" } wordLength=40 generateWordsUntilMatchRegex 'h.*e.*l.*l.*o' generateWordsUntilMatchRegex '^w.*[orl].*d$'
#!/usr/bin/env bash trap "{ echo 'CTRL-C detected... Bye-bye.'; exit 1; }" SIGINT # This function is the job to redo if failed doSomething() { random=$RANDOM echo "I'm working with '$1' and '$2' and '$3' (RANDOM = $random)" echo [ $random -lt 10 ] && return 0 || return 1 } loopNumber=1 until doSomething 'foo' 'bar' 42; do echo "$loopNumber loops so far, and running ..." loopNumber=$((loopNumber+1)) done echo "DONE !" echo "In $loopNumber loops "
tmpFile=$(mktemp) echo -e 'Bob\nKevin\nStuart' > "$tmpFile"; while read name; do echo "Hello, '$name' !" done < "$tmpFile" rm "$tmpFile"
Hello, 'Bob' ! Hello, 'Kevin' ! Hello, 'Stuart' !
tmpFile=$(mktemp) echo -e ' Bob \n Kevin \n Stuart ' > "$tmpFile"; while read name; do echo "Hello, '$name' !" done < "$tmpFile" while IFS= read name; do echo "Hello, '$name' !" done < "$tmpFile" rm "$tmpFile"
Hello, 'Bob' ! Hello, 'Kevin' ! Hello, 'Stuart' ! Hello, ' Bob ' ! Hello, ' Kevin ' ! Hello, ' Stuart ' !
tmpFile=$(mktemp) echo -e 'apples\t12\nbananas\t3\ncoconuts\t42' > "$tmpFile"; while read fruit number; do echo -e "Number of '$fruit' : '$number'" done < "$tmpFile" while read -r fruit number; do echo -e "Number of '$fruit' : '$number'" done < "$tmpFile" rm "$tmpFile"
Number of 'apples' : '12' Number of 'bananas' : '3' Number of 'coconuts' : '42' Number of 'apples' : '12' Number of 'bananas' : '3' Number of 'coconuts' : '42'
while read line; do echo "$line" done < <(ps -u $(whoami) | head -10)
done < <(command)
while read line; do echo "$line" done <<< $(ps -u $(whoami) | head -10)
done <<< $(command)
while read line; do echo "$line" done < <(cat <<-EOF 1 apple 2 bananas 3 coconuts EOF )
for
loop, but the while read
construct allows listing items vertically, making the code more readable, especially if items are long or if they are made of tuples :
while read line; do firstName=$(echo "$line" | cut -d'|' -f1) lastName=$( echo "$line" | cut -d'|' -f2) echo "First name : '$firstName', last name : '$lastName'" done < <(cat <<-EOF Bruce|Banner Lex|Luthor Lois|Lane Peter|Parker EOF )
while read firstName lastName; do echo "First name : '$firstName', last name : '$lastName'" done < <(cat <<-EOF Bruce Banner Lex Luthor Lois Lane Peter Parker EOF )
First name : 'Bruce', last name : 'Banner' First name : 'Lex', last name : 'Luthor' First name : 'Lois', last name : 'Lane' First name : 'Peter', last name : 'Parker'
if condition; then some commands else some different commands fi
{ }
surrounding the then
and else
blocks.until condition do doSomething donewill doSomething
a=5; until [ "$a" -eq 2 ]; do echo $a; a=$((a-1)); done
until ping -c 1 192.168.144.118 & >/dev/null; do echo -n '.'; sleep 1; done; echo OK
url='http://x.y.z.y/page/content/changing/upon/reload/' needle='some text' tmpFile=$(mktemp --tmpdir tmp.XXXXXXXX) loops=0 until grep -i "$needle" $tmpFile; do loops=$((loops+1)) >$tmpFile wget $url -O $tmpFile done echo "Number of loops : $loops"
#!/bin/bash something='hello world' case $something in h*) echo 'foo' ;; *) echo 'bar' ;; esac
foo
;;
can not be omitted to create a "fallback" like in C or with the PHP switch
;;
is the "end of case" operator, but is not the only option available :
;;
: no subsequent matches are attempted after the first pattern match;&
: causes execution to continue with the list associated with the next set of patterns
#!/usr/bin/env bash myFunction() { case "$1" in a) echo a ;; b) echo b ;& c) echo c ;; *) echo star ;; esac echo ----- } myFunction a myFunction b myFunction c myFunction z
a prints then hits;;
→ stop ----- b prints then executes the code of the next case unconditionally c prints then hits;;
→ stop ----- c prints then hits;;
→ stop ----- star prints then hits;;
→ stop -----
;;&
: causes the shell to
#!/usr/bin/env bash myFunction() { case "$1" in a) echo a ;; b) echo b ;;& c) echo c ;; *) echo star ;; esac echo ----- } myFunction a myFunction b myFunction c myFunction z
a prints then hits;;
→ stop ----- b prints then checks whether the next case matches (here, no match) star continue evaluating the following cases : here the*
matches ----- c prints then hits;;
→ stop ----- star prints then hits;;
→ stop -----
#!/usr/bin/env bash listOfCommands=': break continue return exit' for command in $listOfCommands; do echo "With '$command'" for i in {1..3}; do echo -n ' ==> ' [ "$i" -eq 2 ] && eval "$command" echo $i done echo -e 'This comes after the loop\n' done
With ':' ==> 1 ==> 2 nothing special, as expected ==> 3 This comes after the loop With 'break' ==> 1 ==> This comes after the loop stop the whole loop block and continue the script after it With 'continue' ==> 1 ==> ==> 3 skip the rest of the current loop and start the next loop This comes after the loop With 'return' ==> 1 ==> ./test.sh: line 9: return: can only `return' from a function or sourced script complain and interrupt nothing 2 ==> 3 This comes after the loop With 'exit' ==> 1 ==> stop the script, return to the shell prompt