sh Linux.Bash.Loops

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sh Linux.Bash.Loops相关的知识,希望对你有一定的参考价值。

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
~

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

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")

#####
#!/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"

#######

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
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
# 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

# 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


# 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 
         
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
#!/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
# 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 ))

以上是关于sh Linux.Bash.Loops的主要内容,如果未能解决你的问题,请参考以下文章

如何使我的命令行在具有扩展名(.sh)和名称如“weird.sh.sh.sh”的文件上工作

sh sh_template.sh

sh sh.sh

Linux下面如何运行 SH文件

配置告警系统主脚本main.sh mon.sh load.sh 502.sh disk.sh

shell 脚本各种执行方式(source ./*.sh, . ./*.sh, ./*.sh)的区别