For exit bash loop. BASH: description of for, while, until loops and usage examples

And now the turn of the fifth topic of the cycle has come. In it, I will continue to look at the control structures of the bash shell. The previous post covered conditional statements. Now it's time for such integral language structures as loop statements. Loops, like conditions, are tools that provide control over the order in which commands are executed.
Bash supports for, while, until, and select loops. Now let's take a closer look at each of them.

for loop statement

The general syntax of the for statement is:

for variable
do
command list
done

The for loop in bash is quite different from the for loop in programming languages ​​such as C or PHP. So if you're a C programmer, you'll need to get used to these differences so you don't get confused.
As a result of the template substitution, a list of words is obtained. At each iteration, the variable takes on each subsequent value of this list, and the commands between do and done are executed. The iterations stop when the words in the list are exhausted.
$ for day in Mon Tue Wed Thu Fri do echo “Today $day” done
The reserved words of the for statement can also be written in one line, as it was in the previous post for the if statement. To do this, put ";". Let's rewrite the previous example with this feature in mind:
$ for day in Mon Tue Wed Thu Fri; do echo "Today is $day"; done
The absence of a construct is equivalent to writing in $@. The $@ parameter was discussed in .

while loop statement

The general syntax of the while statement is:

while list1
do
list2
done

List1 is executed first. If it succeeds, i.e. returns code zero, control passes to list2. The iterations continue until the result of executing list1 becomes non-zero. For example:
i=10 while [ $i -gt 0 ]; do echo $i i=$(($i-1)) done; echo "end"

until loop statement

The general syntax of the until statement is:

until list1
do
list2
done

List1 is executed first. If it fails, that is, with a non-zero return code, control passes to list2. The iterations continue until the result of list1 execution becomes zero. For example:
i=10 until [ $i -lt 0 ]; do echo $i i=$(($i-1)) done; echo "end"

select loop statement

The general syntax of the select statement is:

select variable
do
list
done

As a result of the template substitution, a list of words is obtained. The operator adds serial numbers to these words and outputs the entire set to the standard error stream. The absence of a construct is equivalent to writing in $@. After that, a prompt is displayed and a line is read from the standard input stream. If the string contains a number corresponding to any word from the list, then the variable gets that number as its value. If a suitable word was not found, then the value of the variable becomes an empty string. After that, the list of commands is executed, and iteration continues until the end-of-file character is found in the input line or until break or return is encountered in the list of commands.
The break and return commands are used to control the progress of the loop. The break command breaks the execution of the loop, while return returns a result code (zero or non-zero).
The select statement is useful for creating numbered menus. For example, in the ~/temp directory there are 3 files: proto.txt, file.txt and readme. An example of a script fragment that allows you to quickly view any of them.
echo "Select file to view:" select file in ~/temp/* Quit; do if [ -f $file ]; then cat $file; else break; fi done
By running this script, we will see on the screen:
Select a file to view:
1) /home/istergul/temp/file.txt
2) /home/istergul/temp/proto.txt
3) /home/istergul/temp/readme
4) Quit

The next topic will look at conditional parameter substitutions. I look forward to your comments.

In this lecture, we continue to get acquainted with bash. I want to remind you that we are considering those elements bash to help us understand scripts operating system. Such elements certainly are cycles and functions. If someone has studied programming, then there will be no difficulty in understanding these issues.

for loop

Cycle for V bash has two types. Consider first the classical version for. The general view is as follows:

Between elements for And in a variable is set, which in turn takes a value from a sequence of values ​​given between in And do. Between do And done there are commands that are executed every time the variable changes its value. The loop stops when the variable takes the last value in the sequence. The values ​​in the sequence are separated by a space.

And here is a practical example:

The sequence of values ​​can be specified in different ways. Explicitly - as in the example above, or with the help of other variables, or with the help of special commands. Let's look at some examples. Since the values ​​are separated by a space, any variable that contains a string with spaces can be used as such values:

The result will be the same as in the first example.

If you need to specify a sequence of numbers, you can use the command seq and substitution mechanism. Team seq returns a sequence of numeric values ​​to the screen. The syntax is simple and will be clear from the example below:

Result:

Let's go back to the second kind. for. Often in scripts you can find the so-called C-like option for, which is used for number-based loops. Let's take a look at an example:

The loop is executed while the condition being checked in the expression is true. As soon as the expression returns false, the loop is terminated.

Practical example:

#!/bin/bash
i=1
while [ $i -lt 7 ]
do
echo $i
let i=i+1
done

In our example, we check that the variable i less than (-lt), the number 7 and if so, then the value of the variable is displayed. Expression let i=i+1, increments the variable by one, checks again, and so on. let tells the interpreter that the arguments should be treated as numeric values. This line could be written as let i++(c-like variant). When the number is increased by more than one, it can be written as: let i+=2- in this case i will increase in steps of 2. Another way to increase a variable is to use the built-in calculator (only works with integers). The calculator can be accessed through double brackets: i=$(($i+1)) or through square: i=$[$i+1] You can also use the calculator on the command line:

With loops, you need to be careful not to get the option of an infinite loop. By the way for debugging bash scripts, you can change the first line to #!/bin/bash -x or run the script with the command bash-x:

[email protected]:~/linux$ bash -x ./testfor.sh
+ i=1
+ ‘[‘ 1 -gt 5 ‘]’
+ echo i=1
i=1
+ let i=i+1
+ ‘[‘ 2 -gt 5 ‘]’
+ echo i=2
i=2
+ let i=i+1
+ ‘[‘ 3 -gt 5 ‘]’
+ echo i=3
i=3
+ let i=i+1
+ ‘[‘ 4 -gt 5 ‘]’
+ echo i=4
i=4
+ let i=i+1
+ ‘[‘ 5 -gt 5 ‘]’
+ echo i=5
i=5
+ let i=i+1
+ ‘[‘ 6 -gt 5 ‘]’

Be sure to practice writing small scripts to solidify your understanding of how loops work in bash.

Functions in bash

Functions apply in bash very wide. Functions are described in two ways: with a keyword function, and without it.

First way:

function function_name
{
function body
}

Second way:

function_name()
{
function body
}

The function is called by name anywhere in the script, but only after the description of the function itself. Functions can also be passed parameters, which are specified with a space after the call (name) of the function. Consider an example script bash:

#!/bin/bash
function primer
{
if [ $# -ne 0 ]
then
local a=1
echo "Number of parameters passed - $#"
for i in $@
do
echo "$ a-th parameter— $i"
let a++
done
return 0
else
echo "No parameters passed"
return 1
fi
}
echo "Calling a function with parameters:"
primer a b c
echo $?
echo "Calling a function without parameters:"
primer
echo $?

IN this example given a function named primer. Calling a function with parameters: primer a b c and without parameters: primer. In the body of the function, all the constructs should be familiar to you, with the exception of $# , $i And $@ .$# - returns the number of parameters passed to the function. In our example, this will be the number 3 .$@ returns all parameters in one line. In the example this would be a b c. And through $1 , $2 , $3 etc. you can access each parameter individually. $? - contains the execution code of the last command. In our example, the function execution code.

The function may also return numerical value via keyword return. As a rule, they return 0 if the function completed without errors, or a non-zero value if something went wrong. In the example, in case of a function call with parameters, the value 0 is returned, and if the function was called without parameters, the code 1 will be returned.

Everything about passing parameters to a function works exactly the same for a script. You can also pass parameters to a script and manipulate them in the same way using $#, $@, $N. From the same category and option - $0 - which returns the name of the command that launched the script. If the script was run on command ./script.sh, then echo $0 will return a value ./script.sh, and if on command /home/igor/linux/script.sh, then the value will be returned /home/igor/linux/script.sh.

One of the basic rules of system administration can be expressed as follows: if you need to do the same thing often, write a script and let it do the work for you. If you need to perform some action within the script several times, then you should use cycles. IN GNU Bash you can create loops with constructs for, while And until.

If you've ever been interested in programming, chances are you're already familiar with these constructs. If, like me, you are studying bash If you have no programming experience behind you, the use of loops may not be obvious enough to understand. Let's start by identifying the differences between various types cycles, and then move on to examples.

Cycle for is designed to repeat actions until they are all completed. Imagine, for example, that you have a directory of images and you need to convert them from one format to another. You can use a loop for together with the program convert from the package ImageMagick(or some other program), for example, in order to convert images from JPEG format to PNG format. Or, for example, you may need to convert a lot of sound files from MP3 V OGG Vorbis.

Cycle while used to repeat actions Bye performed (is true) some condition. Cycle until works a little differently: it performs an action until until the condition is met. So, for example, you can counter and perform an action until until its value reaches 10. Let's look at this in more detail with examples.

Let's start with a loop for. Its format is:

For i in $(command); do command $i; done

If you are using a loop for in a script, it's better to format it like this:

#!/bin/bash for i in $(command); do command $i done

So, for example, if you need to do backups all HTML files in the directory, you can use the following command:

For i in $(ls *html); do cp $i $i.bak; done

This creates a local variable $i, the command is executed ls*html, the results of which will be the data that initializes the value of the variable $i at each iteration of the loop (in our example, this will be the list of files returned by the command ls, one for each iteration). Next, the command is executed cp, to which a variable is passed among the parameters $i.

Someone might ask if it is mandatory to use the letter "i" as a variable name? No. You can use any valid bash variable name. Of course, it is better to use more meaningful variable names in scripts, like $input or $html.

I gave a very short and simple example of using a loop for. Instead of a command executing in a block do,use echo in order to see the parameters passed to it. This is a very useful practice at the stage of testing scripts, as well as good way help you understand your work in more detail for.

while and until

Consider now the constructions while And until. Also, we'll make some use of bash conditionals. In our example, we will use them to determine, for example, whether the value of a variable is greater or less than the number X; whether the file exists and whether it is a directory. You can also use conditionals to determine, for example, whether a file is readable or has a GID bit in its permissions.

Let's try to do something simple like create some empty files. In life, this is unlikely to be useful to you, but as an example, it is the very thing.

#!/bin/bash i=0 while [ $i -lt 22 ] do touch $i i=$[$i+1] done

This script will create 22 files with names from 0 to 21. The loop will run until Bye variable value $i less ( -lt) 22.

Now let's get rid of the generated files with a loop until:

#!/bin/bash i=0 until [ $i -eq 22 ] do rm $i i=$[$i+1] done

Here we have replaced while on until, and in the conditional expression we replaced "less" (-lt) on "equals" (-eq). Thus, our script will work as long as the value $i will not reach 22. And instead of touch we used rm to delete files instead of creating them. Simple, right?

Loops are an extremely convenient thing when writing any programs or scripts, or rather a necessary one. They allow us to execute some piece of code a given number of times. Naturally bash has several kinds of loops. We will describe cycles for in, for, while, until. Although for in and for are considered different syntaxes for the same statement, in my opinion they differ from each other more than while from until.

Loop with counter for in:

Cycle for in it's a loop with a counter. The block of code located in the body of the loop is repeated as many times as there are values ​​in the list of the for in operator, while at each repetition the counter variable (here it is called var, but of course you can call it whatever you like) has the value of the next element of the list.
If the keyword do is on the same line as the word for, then after the list of arguments (before do) you must put a semicolon.
Each of the elements<список>may contain multiple arguments. This is useful when processing parameter groups. In this case, to force parsing of each of the arguments in<списке>, you must use the set statement
You can use a variable as a list in a for loop.
IN<списке>for loops, file names can be used, which in turn can contain wildcard characters. This can be very useful when working with a large number of files.
If<список>is not specified in the for loop, then the variable $@ is used as it - the list of command line arguments.
When creating a list of arguments, command substitution can be used in the for loop.
The output of the loop can be redirected from stdout to a file or somewhere else (you can learn more about this by parsing I / O redirection).

Syntax:
for var in<список>
do
<выполняемые команды>
done

Example:
for names in name1 name2 name3 name4
do
echo $names
done

Loop statement for has another way of writing - very similar to the syntax of the for operator in the C language. In this case, when initializing the counters, the initial values ​​\u200b\u200bof variables or one variable are set and after each pass of the loop the condition is checked, if the check returns true, then the next pass of the loop begins. In the block<приращение счётчиков>the value of our variable counters must necessarily change (not necessarily upwards) so that when checking the condition, sooner or later we get the value of lies, otherwise the loop will never end. A very convenient and most importantly familiar option, if any operation needs to be repeated a specified number of times.

With a similar syntax:
for ((<инициализация счётчиков>; <проверка условия>; <приращение счётчиков>))
do
<выполняемые команды>
done

Example:
for ((var=1; var<= LIMIT ; var++))
do
echo $var
done

while loop:

This is a fairly simple construction that checks the condition behind the operator while and if this condition is true, it executes the block of commands located between the words do and done and then again proceeds to check the condition. If the check returns false, then the loop ends and the following commands are executed: done. It is necessary to ensure that<проверка условия>depended on the code running in the loop otherwise, if the result of the check does not change, you will get an infinite loop.
Standard input, for a while loop, can be redirected to a file using the redirect command< в конце цикла.

Syntax:
while<Проверка условия>
do
<Блок команд, обязательно меняющий переменные влияющие на проверку условия>
done

Example:
while [ $var0 -eq 100 ]
do
echo $var
var++
done

Operator while may have multiple conditions. But only the last of them determines the possibility of continuing the cycle. In this case, the syntax of the loop statement will be different from the usual one.
Syntax(I repeat once again that only the last condition affects the execution of the loop) :
while
<условие1>
<условие2>

<условиеN>
do
<выполняемые команды - тело цикла>
done

until loop:

Operator until very similar to while, it also evaluates the condition, but executes the body of the loop if the result of the calculation is false. It may seem strange, but until evaluates the condition before the first iteration of the loop, like while, and not after it. As with for/in loops, when placing the do keyword on the same line as the loop declaration, you must insert the character ";" before do.
As in the previous case, it is important to remember that the condition must depend on the operations in the loop body, otherwise our script will never end.

Syntax:
until<Проверка условия>
do
<Блок команд, обязательно меняющий переменные влияющие на проверку условия>
done

Example:
until [ $var0 -gt 100] # The condition is checked at the beginning of the iteration.
do
echo $var
var--
done

Probably enough for now. :)

  • Back
  • Forward

New articles:

  • Network discovery does not turn on in Windows 7/8/2008/2012
  • Error: This application failed to start because it could not find or load the Qt platform plugin "windows".
  • Configuring automatic restart of work processes rphost.exe server 1C 8.3
  • How to reduce the size of the transaction log (.ldf) in MS SQL 2008/20012

    MS SQL, like any decent industrial DBMS, along with the database, keeps transaction logs that allow you to roll back the state ...

5

Your script is coded in a dangerous way.

First, I'm assuming you're using the Bash shell since you marked it with "/bash" and "/for".

In my answer, I'll quote this great Bash guide, which is probably the best source for learning Bash.

1) Never use Command Substitution , out or kind, without quotes. There is a big problem here: using an unquoted expansion to split output into arguments.

To be specific, this $(find$ DIRWORK -type d -name work) and $(find$ DIR -type f) will undergo Word Splitting , thus if find finds a file with spaces in its name i.e. "filename" word splitting the result of Bash will pass 2 arguments to the for command to iterate over, i.e. one for "file" and one for "name". In this case, you want to hope you get "file: no such file or directory" and "name: no such file or directory" rather than potentially damaging them if they do exist.

2) By convention, environment variables (PATH, EDITOR, SHELL, ...) and internal shell variables (BASH_VERSION, RANDOM, ...) are fully capitalized. All other variable names must be lowercase. Since variable names are case sensitive, this convention avoids accidental redefinition of environmental and internal variables.

This is a safer version of your script that I recommend you use instead:

My_home="/root/mydir" my_dir=" $my_home/var" dir_work="$ my_home/Local" while IFS= read -r -d "" f; do # I"m guessing that you also want to ignore stderr; # this is where the 2>&1 came from. if lsof -n " ​​$f" | grep "" > /dev/null 2> then echo "hey, I "m safer now!" fi done< <(find "$ dir_work" -type f -print0) while IFS= read -r -d "" f; do echo "2" done < <(find "$dir_work" -type d -name "work" -print0)

As you can see, the IFS variable is set to empty, thus preventing read from trimming the leading and trailing spaces from the string. the read command uses the empty string (-d "") as a delimiter to read until it reaches a \ 0. find must be m respectively, so it uses the -print0 option to delimit its data with \ 0 instead of a newline, which is , surprisingly and maliciously, can be part of the filename. Splitting such a file into \n into two parts will break our code.

The previous answer, which states that find ... | while readname; do ...; done should be used to read find s the output can be bad as well. The while loop executes in a new subshell with its copy of the variables copied from the parent. This copy is then used for whatever you like. When the while loop is finished, the copy of the subshell will be discarded and the parent's original variables will not be changed.

If you intend to change some variables inside this while loop and use them later in the parent, consider using a safer script that will prevent data loss.

0

"Never use Command Substitution, of any kind, without quotes." It's just nitpicking, but it's possible to use command substitution without quotes when you set a variable: "something = $(basename" filename with spaces ")". - Smith John 22 Apr. 13 2013-04-22 21:43:10

2

For i in $(find$ DIRWORK -type d -name work); do echo "2" done

will be the first to execute this line

Find $DIRWORK -type d -name work

wait until find finishes executing and then take the output and put it back in the for loop

For i in the output of find; do echo "2" done

only then will the for loop begin executing.

So if find takes a long time to complete the for loop, it must wait a long time before it can start.

Try temporary find commands interactively

$ time find $DIRWORK -type d -name work

and see how long it takes.

Also note that you should not use a for loop to iterate over filenames. Use a while loop with read , like this:

Find$ DIRWORK -type d -name work | while readname; do echo "2" done

Bonus: it executes the while loop in parallel with find . This means that the while loop will execute one iteration as soon as find prints one line. You don't have to wait for find to complete execution.

mob_info