Skip to content

Instantly share code, notes, and snippets.

@onlyforbopi
Last active August 15, 2022 15:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save onlyforbopi/1eb70bbf2fb9e686f4e5d597773232cd to your computer and use it in GitHub Desktop.
Save onlyforbopi/1eb70bbf2fb9e686f4e5d597773232cd to your computer and use it in GitHub Desktop.
Linux.Bash.Loops #linux #bash #loop #loops #for #while #iteration 1. While with multiple conditions 2. For Loop + Examples 3. While Loop + Examples 4. Until Loop + Examples 5. Loop Break + Examples 6. Loop Continue + Examples 7. Select statement + E
#!/bin/bash
# Make a backup set of files
for value in $1/*
do
used=$( df $1 | tail -1 | awk '{ print $5 }' | sed 's/%//' )
if [ $used -gt 90 ]
then
echo Low disk space 1>&2
break
fi
cp $value $1/backup/
done
#!/bin/bash
for i in $( ls ); do
echo item: $i
done
#!/bin/bash
# Basic for loop
names='Stan Kyle Cartman'
for name in $names
do
echo $name
done
echo All done
#!/bin/bash
# Basic range in for loop
for value in {1..5}
do
echo $value
done
echo All done
#!/bin/bash
# Basic range with steps for loop
for value in {10..0..2}
do
echo $value
done
echo All done
#!/bin/bash
# Make a php copy of any html files
for value in $1/*.html
do
cp $value $1/$( basename -s .html $value ).php
done
#!/bin/bash
# Make a php copy of any html files
for value in $1/*.html
do
cp $value $1/$( basename -s .html $value ).php
done
To Iterate Through Array Values
Use for loop syntax as follows:
for i in "${arrayName[@]}"
do
:
# do whatever on $i
done
$i will hold each item in an array. Here is a sample working script:
#!/bin/bash
# declare an array called array and define 3 vales
array=( one two three )
for i in "${array[@]}"
do
echo $i
done
while read p; do
echo "$p"
done <peptides.txt
########
while IFS="" read -r p || [ -n "$p" ]
do
printf '%s\n' "$p"
done < peptides.txt
########
while read -u 10 p; do
...
done 10<peptides.txt
########
cat peptides.txt | while read line
do
# do something with $line here
done
########
#!/bin/bash
filename='peptides.txt'
echo Start
while read p; do
echo $p
done < $filename
##########
#!/bin/bash
filename='peptides.txt'
exec 4<$filename
echo Start
while read -u4 p ; do
echo $p
done
##########
#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
echo "$line"
done < "$1"
##########
#!/bin/bash
#
# Change the file name from "test" to desired input file
# (The comments in bash are prefixed with #'s)
for x in $(cat test.txt)
do
echo $x
done
##########
Option 2: For loop: Read file into single variable and parse.
This syntax will parse "lines" based on any white space between the tokens. This still works because the given input file lines are single-word tokens. If there were more than one token per line, then this method would not work. Also, reading the full file into a single variable is not a good strategy for large files.
#!/bin/bash
filename='peptides.txt'
filelines=`cat $filename`
echo Start
for line in $filelines ; do
echo $line
done
###########
for word in $(cat peptides.txt); do echo $word; done
###
for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done
#####
for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done > outfile.txt
#####
while IFS= read -r line; do
echo "$line"
done <file
#####
# delimited file
# ':' is the delimiter here, and there are three fields on each line in the file
# IFS set below is restricted to the context of `read`, it doesn't affect any other code
while IFS=: read -r field1 field2 field3; do
# process the fields
# if the line has less than three fields, the missing fields will be set to an empty string
# if the line has more than three fields, `field3` will get all the values, including the third field plus the delimiter(s)
done < input.txt
######
# iterating over output of another command
Reading from the output of another command, using process substitution
while read -r line; do
# process the line
done < <(command ...)
######
# reading from null delimited input
while read -r -d '' line; do
# logic
# use a second 'read ... <<< "$line"' if we need to tokenize the line
done < <(find /path/to/dir -print0)
#######
# reading from more than one file at a time
while read -u 3 -r line1 && read -u 4 -r line2; do
# process the lines
# note that the loop will end when we reach EOF on either of the files, because of the `&&`
done 3< input1.txt 4< input2.txt
#########
# reading entire file into array
while read -r line; do
my_array+=("$line")
done < my_file
If the file ends with an incomplete line (newline missing at the end), then:
while read -r line || [[ $line ]]; do
my_array+=("$line")
done < my_file
#!/bin/bash
for filename in /Data/*.txt; do
for ((i=0; i<=3; i++)); do
./MyProgram.exe "$filename" "Logs/$(basename "$filename" .txt)_Log$i.txt"
done
done
#####
#!/bin/bash
for filename in $(find /Data/*.txt 2> /dev/null); do
for ((i=0; i<=3; i++)); do
./MyProgram.exe "$filename" "Logs/$(basename "$filename" .txt)_Log$i.txt"
done
done
#####
for f in file1 file2 file3 file5
do
echo "Processing $f"
# do something on $f
done
#####
FILES="file1
/path/to/file2
/etc/resolv.conf"
for f in $FILES
do
echo "Processing $f"
done
You can loop through all files such as *.c, enter:
$ for f in *.c; do echo "Processing $f file.."; done
######
#!/bin/bash
FILES=/path/to/*
for f in $FILES
do
echo "Processing $f file..."
# take action on each file. $f store current file name
cat $f
######
#!/bin/bash
while IFS= read -r file
do
[ -f "$file" ] && rm -f "$file"
done < "/tmp/data.txt"
######
#!/bin/bash
_LIGHTTPD_ETC_DEL_CHROOT_FILES="/usr/local/nixcraft/conf/apache/secure/db/dir.etc.list"
secureEtcDir(){
local d="$1"
local _d="/jails/apache/$d/etc"
local __d=""
[ -f "$_LIGHTTPD_ETC_DEL_CHROOT_FILES" ] || { echo "Warning: $_LIGHTTPD_ETC_DEL_CHROOT_FILES file not found. Cannot secure files in jail etc directory."; return; }
echo "* Cleaning etc FILES at: \"$_d\" ..."
while IFS= read -r file
do
__d="$_d/$file"
[ -f "$__d" ] && rm -f "$__d"
done < "$_LIGHTTPD_ETC_DEL_CHROOT_FILES"
}
secureEtcDir "nixcraft.net.in"
#######
The keys are accessed using an exclamation point: ${!array[@]}, the values are accessed using ${array[@]}.
You can iterate over the key/value pairs like this:
for i in "${!array[@]}"
do
echo "key : $i"
echo "value: ${array[$i]}"
done
#####
you can access the keys with ${!array[@]}:
bash-4.0$ echo "${!array[@]}"
foo bar
Then, iterating over the key/value pairs is easy:
for i in "${!array[@]}"
do
echo "key :" $i
echo "value:" ${array[$i]}
done
#######
accepted
The keys are accessed using an exclamation point: ${!array[@]}, the values are accessed using ${array[@]}.
You can iterate over the key/value pairs like this:
for i in "${!array[@]}"
do
echo "key : $i"
echo "value: ${array[$i]}"
done
#######
declare -a arr
echo "-------------------------------------"
echo "Here another example with arr numeric"
echo "-------------------------------------"
arr=( 10 200 3000 40000 500000 60 700 8000 90000 100000 )
echo -e "\n Elements in arr are:\n ${arr[0]} \n ${arr[1]} \n ${arr[2]} \n ${arr[3]} \n ${arr[4]} \n ${arr[5]} \n ${arr[6]} \n ${arr[7]} \n ${arr[8]} \n ${arr[9]}"
echo -e " \n Total elements in arr are : ${arr[*]} \n"
echo -e " \n Total lenght of arr is : ${#arr[@]} \n"
for (( i=0; i<10; i++ ))
do echo "The value in position $i for arr is [ ${arr[i]} ]"
done
for (( j=0; j<10; j++ ))
do echo "The length in element $j is ${#arr[j]}"
done
for z in "${!arr[@]}"
do echo "The key ID is $z"
done
~
#!/bin/bash
foo=string
for (( i=0; i<${#foo}; i++ )); do
echo "${foo:$i:1}"
done
######
while read -n1 character; do
echo "$character"
done < <(echo -n "$words")
Note the use of echo -n to avoid the extraneous newline at the end. printf is another good option and may be more suitable for your particular needs. If you want to ignore whitespace then replace "$words" with "${words// /}".
Another option is fold. Please note however that it should never be fed into a for loop. Rather, use a while loop as follows:
while read char; do
echo "$char"
done < <(fold -w1 <<<"$words")
#####
for var in "$@"
do
echo "$var"
done
####
#this prints all arguments
while test $# -gt 0
do
echo $1
shift
done
####
argc=$#
argv=($@)
for (( j=0; j<argc; j++ )); do
echo ${argv[j]}
done
##
# Under development
aparse() {
while [[ $# > 0 ]] ; do
case "$1" in
--arg1)
varg1=${2}
echo $varg1
shift
;;
--arg2)
varg2=true
echo $varg2
;;
esac
shift
done
}
aparse "$@"
# Better version
#!/bin/bash
PARAMS=""
while (( "$#" )); do
case "$1" in
-f|--flag-with-argument)
FARG=$2
shift 2
;;
--) # end argument parsing
shift
break
;;
-*|--*=) # unsupported flags
echo "Error: Unsupported flag $1" >&2
exit 1
;;
*) # preserve positional arguments
PARAMS="$PARAMS $1"
shift
;;
esac
done
# set positional arguments in their proper place
eval set -- "$PARAMS"
There’s a lot going on here so let’s break it down. First we set a variable `PARAMS` to save any positional arguments into for later. Next, we create a while loop that evaluates the length of the arguments array and exits when it reaches zero. Inside of the while loop, pass the first element in the arguments array through a case statement looking for either a custom flag or some default flag patterns. If the statement matches a flag, we do something (like the save the value to a variable) and we use the `shift` statement to pop elements off the front of the arguments array before the next iteration of the loop. If the statement matches a regular argument, we save it into a string to be evaluated later. Finally, after all the arguments have been processed, we set the arguments array to the list of positional arguments we saved using the `set` command.
###############################
# for i
107
down vote
Note that Robert's answer is correct, and it works in sh as well. You can (portably) simplify it even further:
for i in "$@"
is equivalent to:
for i
I.e., you don't need anything!
Testing ($ is command prompt):
$ set a b "spaces here" d
$ for i; do echo "$i"; done
a
b
spaces here
d
$ for i in "$@"; do echo "$i"; done
a
b
spaces here
d
I first read about this in Unix Programming Environment by Kernighan and Pike.
In bash, help for documents this:
for NAME [in WORDS ... ;] do COMMANDS; done
If 'in WORDS ...;' is not present, then 'in "$@"' is assumed.
#######
#!/bin/bash
# make sure you always put $f in double quotes to avoid any nasty surprises i.e. "$f"
for f in $*
do
echo "Processing $f file..."
# rm "$f"
done
OR
#!/bin/bash
# make sure you always put $f in double quotes to avoid any nasty surprises i.e. "$f"
for f in $@
do
echo "Processing $f file..."
# rm "$f"
done
Please note that $@ expanded as “$1” “$2” “$3” … “$n” and $* expanded as “$1y$2y$3y…$n”, where y is the value of IFS variable i.e. “$*” is one long string and $IFS act as an separator or token delimiters.
The following example use shell variables to store actual path names and then files are processed using the for loop:
#!/bin/bash
_base="/jail/.conf"
_dfiles="${base}/nginx/etc/conf/*.conf"
for f in $_dfiles
do
lb2file="/tmp/${f##*/}.$$" #tmp file
sed 's/Load_Balancer-1/Load_Balancer-2/' "$f" > "${lb2file}" # update signature
scp "${lb2file}" nginx@lb2.nixcraft.net.in:${f} # scp updated file to lb2
rm -f "${lb2file}"
done
Updated for accuracy!
#!/bin/bash
# A simple menu system
names='Kyle Cartman Stan Quit'
PS3='Select character: '
select name in $names
do
if [ $name == 'Quit' ]
then
break
fi
echo Hello $name
done
echo Bye
#!/bin/bash
COUNTER=20
until [ $COUNTER -lt 10 ]; do
echo COUNTER $COUNTER
let COUNTER-=1
done
counter=1
until [ $counter -gt 10 ]
do
echo $counter
((counter++))
done
echo All done
#!/bin/bash
COUNTER=0
while [ $COUNTER -lt 10 ]; do
echo The counter is $COUNTER
let COUNTER=COUNTER+1
done
#!/bin/bash
# Basic while loop
counter=1
while [ $counter -le 10 ]
do
echo $counter
((counter++))
done
echo All done
# Single POSIX test command with -o operator (not recommended anymore).
# Quotes strongly recommended to guard against empty or undefined variables.
while [ "$stats" -gt 300 -o "$stats" -eq 0 ]
# Two POSIX test commands joined in a list with ||.
# Quotes strongly recommended to guard against empty or undefined variables.
while [ "$stats" -gt 300 ] || [ "$stats" -eq 0 ]
# Two bash conditional expressions joined in a list with ||.
while [[ $stats -gt 300 ]] || [[ $stats -eq 0 ]]
# A single bash conditional expression with the || operator.
while [[ $stats -gt 300 || $stats -eq 0 ]]
# Two bash arithmetic expressions joined in a list with ||.
# $ optional, as a string can only be interpreted as a variable
while (( stats > 300 )) || (( stats == 0 ))
# And finally, a single bash arithmetic expression with the || operator.
# $ optional, as a string can only be interpreted as a variable
while (( stats > 300 || stats == 0 ))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment