Shell command language. What to study next? Let's get started: sign in and sign out

As mentioned above, to build arbitrary algorithms it is necessary to have condition checking operators. Shell bash supports selection statements ifthenelse and case, as well as looping operators for,while, until, making it a powerful programming language.

5.8.1 Operators if And test(or )

Design conditional operator in slightly simplified form it looks like this:

if list1 then list2 else list3 fi

Where list1, list2 and list3 are sequences of commands separated by commas and ending with a semicolon or newline character. Additionally, these sequences can be enclosed in curly braces: (list).

Operator if checks the value returned by commands from list1. If there are several commands in this list, then the value returned by the last command in the list is checked. If this value is 0, then commands from list2; if this value is not zero, the commands from list3. The value returned by such a compound operator if, is the same as the value produced by the last command of the executed sequence.

Full command format if has the form:

if list then list [ elif list then list ] ... [ else list ] fi

(here the square brackets only mean that what is contained in them is not necessarily present in the operator).

As an expression that comes immediately after if or elif, a frequently used command test, which can also be denoted by square brackets. Team test evaluates some expression and returns 0 if the expression is true and 1 otherwise. The expression is passed to the program test as an argument. Instead of writing

test expression,

You can enclose the expression in square brackets:

[expression].

Please note that test and [ are two names of the same program, not some magical conversion performed by the shell bash(only the [ syntax requires that a closing parenthesis be supplied). Note also that instead of test in design if any program can be used.

In conclusion, we give an example of using the operator if:

if [ -e textmode2.htm ] ; then

ls textmode*

else

pwd

About the operator test(or […]) we need to have a special conversation.

5.8.2 Operator test and conditionals

Conditional expressions used in the statement test, are built on the basis of checking file attributes, string comparisons and ordinary arithmetic comparisons. Complex expressions are constructed from the following unary or binary operations("elementary bricks"):

    A file

True if a file named file exists.

    B file

True if file exists and is a special block device file.

    C file

True if file exists and is a special character device file.

    D file

True if file exists and is a directory.

    E file

True if the file named file exists.

    F file

True if the file named file exists and is a regular file.

    G file

True if the file named file exists and its group change bit is set.

    H file or -L file

True if the file named file exists and is a symbolic link.

    K file

True if the file named file exists and its "sticky" bit is set.

    P file

True if the file named file exists and is named pipe(FIFO).

    R file

True if the file named file exists and has read permission set

    S file

True if the file named file exists and its size is greater than zero.

    Tfd

True if the file descriptor fd is open and points to the terminal.

    U file

True if the file named file exists and its change user bit is set.

    W file

True if the file named file exists and has write permission set.

    X file

True if the file named file exists and is executable.

    O file

True if the file named file exists and is owned by the user pointed to by the effective user ID.

    G file

True if the file named file exists and belongs to the group identified by the effective group ID.

    S file

True if the file named file exists and is a socket.

    N file

True if the file named file exists and has changed since it was last read.

    file1 -nt file2

True if the file file1 has a later modification time than file2.

    file1 -ot file2

True if the file file1 older than file2.

    file1 -ef file2

True if the files file1 And file2have the same device and inode numbers(inode).

    O optname

True if the shell option is enabled optname. See the bash man page for an explanation.

    Z string

True if the length of the string is zero.

    N string

True if the length of the string is not zero.

    string1 == string2

True if the strings match. Instead of == can be used = .

    string1 !== string2

True if the strings do not match.

    string1< string2

True if the line string1 lexicographically precedes the string string2(for the current locale).

    string1 > string2

True if the line string1 lexicographically comes after the line string2(for the current locale).

    arg1 OP arg2

Here OP- uh then one of the arithmetic comparison operations: -eq(equals), -ne(not equal), -lt(less than), -le(less or equal), -gt(more), -ge(more or equal). Positive or negative integers can be used as arguments.

From these elementary conditional expressions you can build as complex as you like using the usual logical operations of NEGATION, AND and OR:

    !(expression)

Boolean negation operator.

    expression1 -a expression2

Boolean operator AND(AND). True if both expressions are true.

    expression1 -o expression2

Boolean operator OR(OR). True if either of the two expressions is true.

The same conditional expressions are used in operators while And until, which we will look at below.

5.8.3 Operator case

Operator format case is:

case word in [ [(] pattern [ | pattern ] ...) list ;; ]...esac

Team case first produces word expansion word, and tries to match the result with each of the samples pattern one by one. After the first match is found, no further checks are performed; the list of commands following the pattern with which the match was found is executed. The value returned by the operator is 0 if no pattern matches were found. Otherwise, the value produced by the last command in the corresponding list is returned.

The following example of using the case statement is taken from the system script /etc/rc.d/rc.sysinit.

case "$UTC" in

yes|true)

CLOCKFLAGS="$CLOCKFLAGS -u";

CLOCKDEF="$CLOCKDEF (utc)";

no|false)

CLOCKFLAGS="$CLOCKFLAGS --localtime";

CLOCKDEF="$CLOCKDEF (localtime)";

esac

If the variable evaluates to yes or true, then the first pair of commands will be executed, and if its value is no or false, the second pair will be executed.

5.8.4 Operator select

Operator select allows you to organize interactive interaction with the user. It has the following format:

select name [in word; ] do list ; done

First from the template word a list of words matching the pattern is generated. This set of words is output to the standard error stream, with each word accompanied by a sequence number. If the pattern word omitted, positional parameters are derived in the same way. The standard PS3 prompt is then issued and the shell waits for a line to be entered on standard input. If the entered string contains a number corresponding to one of the displayed words, then the variable name is assigned a value equal to that word. If an empty line is entered, the numbers and corresponding words are displayed again. If any other value is entered, the variable name is assigned a value of zero. The string entered by the user is stored in a variable REPLY. List of commands list executed with the selected variable value name.

Here's a small script:

#!/bin/sh

echo "Which OS do you prefer?"

select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do

break

done

echo "You would choose $var"

Which OS do you prefer?
1) Linux
2) Gnu Hurd
3) Free BSD
4)Other
#?

Press any of the 4 suggested numbers (1,2,3,4). If you enter 1, for example, you will see the message:

“Would you choose Linux”

5.8.5 Operator for

Operator for works a little differently than in regular programming languages. Instead of increasing or decreasing the value of some variable by one each time it passes through the loop, it assigns the next value from a given list of words to the variable each time it passes through the loop. In general, the design looks something like this:

for name in words do list done.

Rules for constructing command lists ( list) are the same as in the operator if.

Example. The following script creates the files foo_1, foo_2 and foo_3:

for a in 1 2 3 ; do

touch foo_$a

done

In general for statement has the format:

for name [in word; ] do list ; done

First, the word is revealed word in accordance with the expression disclosure rules given above. Then the variable name the resulting values ​​are assigned one by one, and a list of commands is executed each time ist. If " in word" is missing, then the list of commands list is executed once for each positional parameter that is specified.

Linux has a program seq, which takes two numbers as arguments and produces a sequence of all numbers located between the given ones. With this command you can force for V bash work exactly the same way as a similar operator works in conventional programming languages. To do this, just write the cycle for in the following way:

for a in $(seq 1 10) ; do

cat file_$a

done

This command displays the contents of 10 files: " file_1", ..., "file_10".

5.8.6 Operators while And until

Operator while works like if, only executing operators from the list list2 loop continues as long as the condition is true and aborts if the condition is not true. The design looks like this:

while list1 do list2 done.

while [ -d mydirectory ] ; do

ls -l mydirectory >> logfile

echo -- SEPARATOR -- >> logfile

sleep 60

done

Such a program will log the contents of the directory "mydirectory" every minute as long as the directory exists.

Operator until similar to operator while:

until list1 do list2 done.

The difference is that the result returned when executing a list of statements list1, taken with negation: list2 executed if the last command in the list list1 returns a non-zero exit status.

5.8.7 Functions

Syntax

Shell bash allows the user to create their own functions. Functions behave and are used exactly like regular shell commands, meaning we can create new commands ourselves. The functions are constructed as follows:

function name() (list)

And the word function not necessary, name defines the name of the function by which it can be accessed, and the body of the function consists of a list of commands list, located between ( and ). This list of commands is executed every time the name name specified as the name of the command to invoke. Note that functions can be defined recursively, so it is permissible to call the function we define within itself.

Functions are executed in the context of the current shell: to interpret the function new process does not run (unlike executing shell scripts).

Arguments

When a function is called for execution, the function's arguments become positional parameters(positional parameters) for the duration of the function. They are referred to as $n, Where n— the number of the argument we want to access. Argument numbering starts at 1, so $1 - this is the first argument. We can also get all the arguments at once with $* , and the number of arguments using $# . Positional parameter 0 does not change.

If a built-in command occurs in the function body return, the execution of the function is interrupted and control is transferred to the command after the function call. When the function completes, the positional parameters and the special parameter # the values ​​they had before the function started are returned.

Local variables (local)

If we want to create a local parameter, we can use the keyword local. The syntax for specifying it is exactly the same as for regular parameters, only the definition is preceded by a keyword local: local name=value.

Here is an example of specifying a function that implements the command mentioned above seq:

seq()

local I=$1;

while [ $2 != $I ]; do

echo -n "$I ";

I=$(($I + 1))

done;

echo $2

Please note the option -n operator echo, it cancels the newline. Although this is not essential for the purposes we have in mind here, it may be useful for using the function for other purposes.

Factorial calculation function fact

One more example:

fact()

if [ $1 = 0 ]; then

echo 1;

else

echo $(($1 * $(fact $(($1 - 1)))))

This is the factorial function, an example of a recursive function. Note arithmetic expansion and command substitution.

V. Kostromin (kos at rus-linux dot net) - 5.8. Shell as a programming language

What is a shell and why is it needed?

The command shell in any unix-like systems, which includes GNU/Linux, is regular program, launched both in a text console (which is used less and less) and in graphical environment– in the terminal emulator window, available on any Linux system.

Its task is simple and obvious: accept a line (or lines) of input, parse them and, based on the results of this analysis, react accordingly - execute a command, run a program, display a diagnostic message, etc.

In almost all Linux distributions, users are assigned the command command by default. bash shell(Bourne Again SHell is another Bourne shell; Steve Bourne is the author of the first command shell in Unix - sh). In fact, it has become an unofficial standard, and improvements to it functionality continues continuously. There are other command shells - tcsh (version of C-shell), ksh (Korn Shell), zsh, etc. – each has its own advantages and disadvantages, as well as its own fan groups. However, bash is more familiar to the general public with different levels preparation, that’s why I chose it. It is also worth noting that no matter what capabilities the various shells have, they are all compatible with their ideological progenitor - the Bourn Shell (sh). In other words, a script written for sh will work correctly in any modern shell (the reverse is generally not true).

Benefits of the Command Line

The question may arise: why bother with the command line if there are convenient and beautiful graphical interfaces? There are many reasons for this. Firstly, not all operations are more convenient or faster to perform using GUI. Second, every program follows the fundamental principle of Unix systems: do a well-defined job and do it well. In other words, you always understand what happens when you run a particular utility (if something is not entirely clear, you should refer to the man manual). Thirdly, by mastering commands, trying their combinations and combinations of their parameters, the user studies the system, gaining valuable practical experience. You get access to powerful tools such as pipelines that allow you to organize a chain of commands for processing data, I/O redirection tools, and you can also program directly from the command shell. Perhaps it’s worth dwelling on programming in more detail, especially since many system scripts in Linux (for example, startup scripts system services) are written for the shell.

Command shell as a programming language

So, the command shell can be considered as a programming language and as software environment execution simultaneously. Of course, this language is not compiled, but interpreted. It allows the use of variables: system or own. The sequence of execution of program commands is changed using condition checking constructs and selecting the appropriate option: if-then-else and case. While, until, and for loops allow you to automate repetitive actions. It is possible to combine groups of commands into logical blocks. You can even write real functions that pass parameters to them. Thus, all the signs and characteristics of a full-fledged programming language are available. Let's try to get double benefit from this - along with learning the basics of programming, we will automate our daily work.

Hello, World! Simple backup system

About the need for regular Reserve copy Everyone knows the data, but users never have enough time for this boring operation. The solution is simple - organize automatic creation of backup copies. This will be our first shell programming task.

#!/bin/bash # # Backup directories and files from the home directory # This batch script can be run automatically using cron # cd $HOME if [ ! -d archives ] then mkdir archives fi cur_date=`date +%Y%m%d%H%M` if [ $# -eq 0 ] ; then tar czf archive$(cur_date).tar.gz projects bin else tar czf archive$(cur_date).tar.gz $* fi if [ $? = 0 ] ; then mv archive$(cur_date).tar.gz $HOME/archives echo "$cur_date – Backup completed successfully." else echo "$cur_date - ERROR during backup." fi

Any command script (script is a script, as command shell programs are called) begins with an identifier line, in which the command interpreter is explicitly specified, indicating the full path to it. The full path is a sequential listing of all directories, starting from the root, that must be entered to get to the target file, and, of course, the name of this file. Recording the full path is extremely important to uniquely identify each file in the file system hierarchy.

Four lines of comments follow. Once the shell encounters the "#" character, it treats all subsequent characters as comments and completely ignores them until the end of the current line. Therefore, you can start a comment not from the very beginning of the line, but accompany it with some command.

After the comments there is an empty line. It means nothing to the command shell, and no action is taken. In scripts, blank lines are usually inserted to make the code easier to read.

We finally got to the first “real” team. It allows you to change the directory (Change Directory), i.e. move from the current directory to another one passed to the command as an argument. In most cases, the target directory is specified explicitly, for example, cd /tmp or cd projects, but in our case the predefined system variable HOME is used - it contains the full path to the home directory current user, on behalf of which the command script is executed. This eliminates the need to make code changes every time we change users, because the command returns everyone to their personal directory. The dollar sign "$" in front of a variable name means that you need to extract the value contained in that variable and substitute it in place of its name on the command line. It should be especially noted that in a command language, letter case shells are important, i.e. HOME, Home and home are three different variables. By convention, uppercase letters denote the names of system variables: HOME, PATH, EDITOR, etc. This convention does not prevent users from creating their own variables with names from capital letters, but why complicate your life by violating generally accepted norms and rules? It is also not recommended to change the values ​​of system variables unless absolutely necessary. In general, we follow a simple rule: we use system variables for read-only purposes, and if we need our own, we write its name in lowercase letters.

Our first command could be written more briefly:

cd ~

Here the "~" symbol also means the current user's home directory. Command line veterans put it even more succinctly:

CD

The idea is that when the cd command is given no argument, it changes to the home directory.

Next up is the classic software design for checking conditions and making the appropriate decision. General scheme is this:

if<условие>then<одна или несколько команд>fi

The last word of the construction (if in reverse order) acts as a closing parenthesis, i.e. boundaries of the list of commands executed when the condition is true. The presence of fi is mandatory, even if there is only one team on the list.

To check a condition, as a rule, the test command or its alternative form of notation in square brackets is used. In other words, records

if [! -d archives ] if test ! -d archives

absolutely equivalent. I prefer square brackets because they more clearly define the boundaries of the condition being tested. Both the right and left parentheses must be separated from the condition by spaces.

The criteria for checking the condition are determined by various flags. The test command recognizes a very large list of them. In our example, the -d flag is used, which allows us to check whether the name specified after the flag actually matches existing directory(directory). The following flags are most often used when working with files:

F – does it exist regular file with a given name;

R – whether the specified file has the right to read from it;

W – whether the specified file has the right to write to it;

X – whether the specified file has the right to execute it;

S – whether the specified file has a non-zero size.

In our case, the condition is preceded by Exclamation point, denoting the operation of logical negation, so the meaning of the condition being tested becomes completely opposite. Let's try to write down the meaning of these commands in ordinary Russian:

if [! -d archives ] If the archives directory (in the current directory) does not exist, then start executing the command block: mkdir archives create the archives directory (in the current directory) fi end executing the command block.

As you can see, everything turned out to be not so complicated. With a little practice, you can easily read and create similar designs yourself. The directory creation command is so obvious that no further explanation is required.

IN next line we create our own local variable cur_date. In the vast majority of cases, variables are created by simply assigning a specific value, for example:

ten=10 string="This is a line of text"

But in our example it applies little trick. Please note that after the equal sign - the assignment symbol - the command is written in back quotes. This form of notation allows you to assign to a variable not the string itself, but the result of its execution. Here is the output of the date command, which returns the current date and time in a format specified by a list of parameters:

%Y – current year in full form, i.e. of four digits (for example, 2009);

%m – number current month(for example, 09 – for September);

%d – current day number;

%H – current hour in 24-hour format;

%M – current minute.

Thus, if you run the command

cur_date=`date +%Y%m%d%H%M`

on the tenth of September 2009 at 22:45, then the variable cur_date will be assigned string value"200909102245". The purpose of this trick is to create a unique, non-repeating name for the archive file. If you intend to run several instances of the program within one minute, you can improve the uniqueness of the names by adding the current seconds. How? Study the date utility manual (man date) - there is nothing complicated about it.

Before we start creating an archive file, we need to determine which directories we will save in it. For greater flexibility, we can specify a set of directories to be archived by default, but provide the ability to replace this set with a list of directories passed as an argument to our command script. For this purpose, special command shell variables are used: $# – the number of parameters passed to the script and $* – all parameters passed, written in one line format.

if [ $# -eq 0 ] ; then

Checking the condition “if the number of passed parameters is zero”, then execute the following command. Note that the then keyword can be written on the condition line, separated from the conditional expression by a semicolon.

tar czf archive$(cur_date).tar.gz projects bin

The command to create an archive file and compress this file. The tar utility itself does not perform compression, but only collects all specified files and directories into a single tar file. The first flag is intended for this - c (create). Compression performs external program– here it is gzip, called by the second flag - z. If you have the more efficient bzip2 compression program installed on your system, you can take advantage of it by modifying the command as follows:

tar cjf archive$(cur_date).tar.bz2 projects bin

The third flag f indicates that what follows is the name of the archive file, so it is always the last one in the list of flags. Note that when substituting, the variable name is enclosed in curly braces. This is done to explicitly highlight the variable on the line surrounding it, thereby eliminating many potential problems. Extensions archive file are not assigned automatically; you fill in everything you need yourself. I've specified projects and bin as the default directories to archive, but you can write down the names of your most valuable directories here.

The else keyword opens an alternative branch of execution. The commands of this block begin to work if the condition check returns the result “false” (in our example: “the number of parameters passed is non-zero,” i.e. the user specified directory names). In this case the command will look like this:

tar czf archive$(cur_date).tar.gz $*

Here the default directories are replaced by a directory name string accepted externally. It is possible to accept and process each external parameter separately, but it is more convenient for us to pass the entire string.

At the end of the program, another check is performed. In Unix environments, all commands return a completion status code. If the command was successful, it returns code 0, otherwise the exit code will be non-zero. To check the success of the previous archiving command, we will use another special variable $?, which always contains the value of the completion code of the most recent command. If in the variable $? contains 0, i.e. The backup file was successfully created, then we move it to the archive directory:

mv archive$(cur_date).tar.gz $HOME/archives

and display the corresponding message:

echo "$cur_date – Backup completed successfully."

If the check shows that the completion code for the archiving operation is not equal to zero, then an error message is displayed:

echo "$cur_date - ERROR during backup."

This completes our command script.

To check the operation of our program, you need to save the above source in a file called bckp, for example, and then make it executable for convenience:

chmod 750 bckp

and run:

./bckp

to create a backup of the default directories, and

./bckp docs progs works

to create a backup copy of the listed directories (specify the names of the directories that actually exist on your system, otherwise you will receive an error message).

You can place the bckp file in one of the directories specified in the system PATH variable. The most preferred locations are /usr/local/bin or $HOME/bin if you have them. After this you can run bckp as a system command.

How to automate scheduled backup operations

A few words about backup automation. For this purpose, the system serves cron scheduler, which reads work instructions from a special crontab file. To define such instructions, you need to create and edit your crontab file using the command:

crontab -e

Instructions are written in a strictly defined format (fields are separated by spaces):

minutes hours day_of_month month day_of_week command

One option for scheduling backup operations might look like this:

30 23 10,20,30 * * /usr/local/bin/bckp

This means that the backup script (you must provide the full path to this file) will run at 23:30 on the 10th, 20th and 30th of each month, regardless of the day of the week. (Asterisks indicate the entire permissible range of values, in in this case: every month - in the 4th field, any day of the week - in the 5th field)

If you prefer to summarize your results by week, and your system runs 24/7, then it makes sense to schedule backups during off-peak hours:

0 5 * * 3.5 /usr/local/bin/bckp

Here backups will be created at 5:00 on Wednesdays and Fridays in each month (asterisk in the 4th field), regardless of the date (asterisk in the 3rd field).

You can read about all the intricacies of scheduling in the man 5 crontab manual.

Results and conclusions

The backup script discussed in this article has modest functional properties. But that was not his point the main task, but so that the reader understands what can be done in command line, and not only copied and executed the proposed command file, but became interested in expanding its functions and began researching the immense possibilities provided by command shells. And if someone, after reading this article, tries to improve the code given here, or writes own version, or implements his independent idea, then I will consider that the main goal has been achieved.

Resources for download

static.content.url=http://www.site/developerworks/js/artrating/

ArticleID=458335

ArticleTitle=Shell Programming Basics

Language shell programming has several designs that will give flexibility to your programs:

  • Commentaries will allow you to describe the functions of the program;
  • "here document" allows you to include lines in the program's shell that will be redirected as input to some of the program's shell commands;
  • The exit command allows you to terminate the program in the right point and use return codes;
  • The for and while loop constructs allow you to repeat a group of commands in a loop;
  • conditional commands if and case execute a group of commands if some condition is met;
  • The break command allows you to unconditionally exit a loop.

9.3.1. Comments

To place comments in the program, use the # sign. If a # sign appears after a command, the command itself is executed and the comment is ignored. Comment line format:

#comment

9.3.2. "Here document"

"Here document" allows you to place lines in a shell program that are redirected as command input in that program. This is one way to provide input for a command in a shell program without using a separate file. The entry consists of a redirection character<< и разделителя, который указывает начало и конец строк ввода. В качестве разделителя может использоваться один символ или строка символов. Чаще всего это знак!.

The command format is as follows:

Command<...input lines... delimiter

9.3.3. Using ed in a shell program

"Here document" suggests a way to use ed in a shell program. Let's say you want to create a shell program that will call the ed editor, make global changes to a file, write the changes to the file, and then exit ed. The following screen shows the contents of the ch.text program, which performs these tasks:

$ cat ch.text echo Type in the filename read file1 echo Type in the exact text to be changed. read old_text echo Type in the exact new text to replace the above. read new_text ed - $file1<

Note the - (minus) sign in the ed command. This option prevents the character counter from being printed on the screen. Also note the format of the ed command for global replacement:

G/$old_text/s//$new_text/g

The program uses 3 variables: file1, old_text, new_text. When run, this program uses the read command to obtain the values ​​of these variables. These variables contain the following information:
file - name of the file that will be edited;
old_text - text that will be changed;
new_text - new text.

Variables are introduced into the program, here document redirects the global replace command, the write command, and the end command to the ed command. Run the ch.text program. Get the following screen:

$ch.text Type in the filename memo Type in the exact text to be changed. Dear John: Type in the exact new text to replace the above. To what it may concern: $ cat memo To what it may concern: $

9.3.4. Completion codes

Majority shell commands returns codes that indicate whether the command completed successfully. If the return value is 0 (zero), then the command completed successfully. Return codes are not printed automatically, but can be obtained as the value of the special shell $? parameter.

9.3.4.1. Checking completion codes

After running a command interactively, you can see the exit code when you type:

Consider the following example:

$ cat hi This is file hi. $echo$? 0 $ cat hello cat: cannot open hello $ echo $? $2

In the first case, the file hi exists in your directory and you have read permission. Using the cat command you can print the contents of a file. The result of the cat command is the return code 0, which you will get by specifying the $? parameter. In the second case, the file either does not exist or you do not have read permission. cat command prints a diagnostic message and returns code 2.

The shell program exits normally when the last command in the file is executed. However, you can use the exit command to terminate the program. More importantly, you can use the exit command to obtain shell program return codes.

9.3.5. Cycles

The for and while loop statements allow you to execute a command or sequence of commands multiple times.

9.3.5.1. for statement

The for statement executes a sequence of commands for each element of the list. It has the format:

For variable in a_list_of_values do command_1 command_2 . . . last command done

For each iteration of the loop, the next element of the list is assigned to the variable given in the for statement. This variable can be referenced anywhere in commands within a do statement. When constructing each section of commands, you need to make sure that for each do there is a corresponding done at the end of the loop.

The variable can have any name. For example, if your variable is named var, then a reference to $var in the command list will make the value available. If the in operator is omitted, then the value for var will be the set of arguments given in the command and available in special parameter$*. The list of commands between the do and done keywords will be executed for each value.

When the commands are executed for the last element of the list, the program will execute the line below done.

9.3.5.2. while statement

The while loop operator uses 2 groups of commands. It will execute the sequence of commands in the second group (the do ... done list) until the last command in the first group (the while list) returns true, meaning that the expression after the do can be executed.

The general format of the while loop statement is:

While command_1 . . . last command do command_1 . . . last command done

For example, the enter.name program uses a while loop to enter a list of names into a file. The program consists of the following command lines:

$ cat enter.name while read x do echo $x>>xfile done $

Making some additions, we get next program:

$ cat enter.name echo Please type in each person"s name and than a echo Please end the list of names with a<^d>while read x do echo $x>>xfile done echo xfile contains the following names: cat xfile $

Note that after the loop completes, the program executes the commands below done.

The first two echo commands use special characters, so you must use quotes to escape the special meaning. The following screen shows the output of enter.name:

$enter.name Please type in each person"s name and than a Please end the list of names with a<^d>Mary Lou Janice <^d>xfile contains the following names: Mary Lou Janice $

After the loop completes, the program will print out all the names contained in the xfile.

9.3.6. Using /dev/null

The file system has a file /dev/null where you can store unwanted output. For example, if you simply enter the who command, the system will answer who is working on the system. If you redirect the output of this command to /dev/null:

Who > /dev/null

then you won't get an answer.

9.3.7. Conditional statements

if...then statement

The if command tells the shell program to execute the sequence of commands after then if the last command in the if statement's list of commands completed successfully. If constructs end with the fi keyword.

The general format of the if construct is:

If command_1 . . . last command then command_1 . . . last command fi

For example, the search shell program demonstrates the use of the if ... then construct. The search program uses the grep command to search for a word in a file. If grep is successful, the program displays the word found. The screen will look like this:

$ cat search echo Type in the word and the file name. read word file if grep $word $file then echo $word is in $file fi $

This program displays the output of the grep command. If you want to store the system's response to the grep command in your program, use the /dev/null file, changing the if command line to the following:

If grep $word $file > /dev/null

Now run the search command. It will only respond with the message specified after the echo command.

The if ... then ... else construct can execute an alternative set of commands after the else if the if sequence is false. The format of this construct is as follows:

If command_1 . . . last command .linthen command_1 . . . last command else command_1 . . . last command fi

With this construct, you can improve the search program so that it will tell you both the word found and the word not found. In this case, the search program will look like this:

$ cat search echo Type in the word and the file name. read word file if grep $word $file > /dev/null then echo $word is in $file else echo $word is NOT in $file fi $

test command

The test command is used to organize a loop. It tests certain conditions for truth and is useful for organizing conditional constructs. If the condition is true, the loop will continue. If the condition is false, the loop will end and the next command will be executed. Some examples of using the test command:

Test -r file true if the file exists and is readable; test -w file true if the file exists and is writable; test -x file true if the file exists and is executable; test -s file true if the file exists and has at least one character; test var1 -eq var2 true if var1 is equal to var2; test var1 -ne var2 true if var1 is not equal to var2.

Example. Let's create a shell program that moves all executable files from the current directory to your bin directory. To do this, we will use the test -x command to select executable files. The mv.file program will look like this:

$ cat mv.file echo type in the directory path read path for file do if test -x $file then mv $file $path/$file fi done $

The case ... esac construct allows you to select one of several patterns and then execute a list of commands for that pattern. The pattern expression must begin with the in keyword, and a right parenthesis must be placed after the last character of each pattern. The sequence of commands for each pattern ends with two characters;;. The case construct must be terminated with the esac keyword.

The general format of the case construct is:

Case word in pattern1) command line 1 . . . last command line ;;pattern2) command line 1 . . last command line ;;pattern3) command line 1 . . last command line ;; *)command line 1 . . last command line ;;esac

The case construct tries to find a word with the pattern pattern in the first pattern section. If the search is successful, the program executes the command lines after the first pattern until the corresponding characters;;.

If the first template is not found, then the transition to the second template is carried out. If any pattern is found, the program does not consider the remaining patterns, but moves on to the command following esac. The * is used as a pattern to search for any word and thus gives you a set of commands that will be executed if no other pattern is found. Therefore, the asterisk (*) pattern is placed as the last pattern in the case construct so that the other patterns are checked first. This will help you detect incorrect and unexpected input.

Templates can use metacharacters *, ?, . This provides program flexibility.

Let's look at an example. The set.term program sets the TERM variable according to the type of terminal you are using. The following command line is used:

TERM=terminal_name

The * template is the last one in the list of templates. It issues a warning message that there is no matching pattern for the specified terminal type and allows you to complete the case construct.

$ cat set.term echo If you have a TTY 4420 type in 4420 echo If you have a TTY 5410 type in 5410 echo If you have a TTY 5420 type in 5420 read term case term in 4420) TERM-T4 ;; 5410) TERM-T5 ;; 5420) TERM-T7 ;; *) echo not a correcr terminal type ;; esac export TERM echo end of programm $

9.3.8. Unconditional transfer of control

The break command unconditionally stops the execution of any loop in which it is encountered and transfers control to the command following the done, fi, or esac keywords.

In the previous example set.term program, you could use the break command instead of echo to exit the program, as in the following example:

$ cat set.term echo If you have a TTY 4420 type in 4420 echo If you have a TTY 5410 type in 5410 echo If you have a TTY 5420 type in 5420 read term case term in 4420) TERM-T4 ;; 5410) TERM-T5 ;; 5420) TERM-T7 ;; *) break ;; esac export TERM echo end of programm $

The continue command will cause the program to immediately move to the next iteration of the while or for loop without executing the remaining commands in the loop.

  • Tutorial

Why and for whom is the article?

Initially, this was a reminder for students who are starting to work with Unix-like systems. In other words, the article is intended for those who have no previous experience working with the Unix command line, but for one reason or another want or need to learn how to interact effectively with it.

There will be no retelling of mana (documentation), and the article does not in any way cancel or replace reading them. Instead, I will talk about the main things (commands, techniques and principles) that you need to understand from the very beginning of working in the unix shell in order for the work to be effective and enjoyable.

The article concerns full-fledged unix-like environments, with a fully functional shell (preferably zsh or bash) and a fairly wide range of standard programs.

What is shell

Shell (shell, aka “command line”, aka CLI, aka “console”, aka “terminal”, aka “black window with white letters”) is text interface communication with operating system(well, strictly speaking, this is program, which provides such an interface, but now this difference is insignificant).

In general, work through a shell looks like this: the user (i.e. you) enters a command from the keyboard, presses Enter, the system executes the command, writes the result of the execution to the screen, and again waits for input next command.

Typical view shella:

The shell is the primary way to interact with all Unix-like server systems.

Where are command line systems found?

Where a unix shell might be waiting for you, popular options:
  • MacOS (bash);
  • remote access to the server for work or for a personal web project;
  • home file server with remote access;
  • Ubuntu, PC-BSD on laptop/desktop - unix-like systems today are easy to install and use.

What problems are reasonable to solve with a shell?

Natural tasks for which the shell is suitable, useful and indispensable:
  • interactive work in the terminal:
    • performing compilation, running jobs via make;
    • comparison of text files;
    • fast ad-hoc data analysis (number of unique IPs in the log, distribution of records by hours/minutes, etc.);
    • one-time mass actions (kill many processes; if you work with a version control system, reverse or resolve a bunch of files);
    • diagnostics of what is happening in the system (semaphores, locks, processes, descriptors, disk space, etc.);
  • scripting:
    • installation scripts, for which you cannot rely on the presence of other interpreters - this is not for beginners;
    • functions for customizing the interactive shell (affecting the invitation, changing the directory, setting environment variables) are also not exactly for beginners;
    • one-time scripts such as mass file recoding;
    • makefiles.

Absolutely first steps

Let's get started: sign in and sign out

Make sure you know exactly how to start the shell and how to exit it.

If you are working on a machine with Ubuntu installed, you need to launch the Terminal program. When finished, you can simply close the window.

On MacOS - also launch Terminal.

To access a remote server, use ssh (if you have MacOS, Ubuntu or another unix-like system locally) or putty (if you have Windows).

Who am I, where am I?

Run the following commands:
  • hostname - displays the name of the machine (server) you are currently on;
  • whoami - displays your login (your name in the system);
  • tree -d / |less - pseudo-graphic representation of the directory tree on the machine; exit from scrolling - q ;
  • pwd - displays the directory you are currently in; on the command line you cannot be “just like that”, you must be in some directory (=current directory, working directory). The current working directory is probably displayed in your prompt.
  • ls - list of files in the current directory; ls /home - list of files in the specified directory;

Command history (history)

An important property of a full-fledged command line is the command history.

Run several commands: hostname, ls, pwd, whoami. Now press the up key. The previous command appears in the input line. You can use the up and down keys to move forward and backward through the history. When you get to hostname, press Enter - the command will be executed again.

Commands from history can not only be executed repeatedly, but also edited. Scroll through the history to the ls command, add the -l switch to it (it turns out ls -l , there is a space before the minus, but not after). Press Enter - the modified command will be executed.

Scrolling through history, editing and re-executing commands are the most common actions when working on the command line, so get used to it.

Copy-paste

The command line is very text-centric: commands are text, input data for most standard programs is text, and the output is most often text.

The great thing about text is that it can be copied and pasted, and this is true on the command line as well.

Try the command date +"%y-%m-%d, %A"
Did you enter it entirely by hand or copied it from the article? Make sure you can copy it, paste it into a terminal and execute it.

Once you've learned how to use man, make sure you can copy and run example commands from the help. To check, look up the EXAMPLES section in the date program help, copy and run the first example given (just in case: the dollar sign is not part of the command , this is a symbolic image of an input prompt).

How exactly to copy text from the terminal and paste it into the terminal depends on your system and its settings, so give universal instructions, unfortunately, it won't work. On Ubuntu, try this: copy - just select with the mouse, paste - the middle mouse button. If it doesn’t work, or if you have a different system, search the Internet or ask more experienced friends.

Keys and options

As you've explored the history of commands, you've already encountered that the ls command has at least two options. If you call it just like that, it outputs a simple list:

Akira@latitude-e7240: ~/shell-survival-quide> ls Makefile shell-first-steps.md shell-first-steps.pdf shell-survival-quide.md shell-survival-quide.pdf
If you add the -l switch, detailed information is displayed for each file:

Akira@latitude-e7240: ~/shell-survival-quide> ls -l total 332 -rw-rw-r-- 1 akira akira 198 Feb 13 11:48 Makefile -rw-rw-r-- 1 akira akira 15107 Feb 14 22:26 shell-first-steps.md -rw-rw-r-- 1 akira akira 146226 Feb 13 11:49 shell-first-steps.pdf -rw-rw-r-- 1 akira akira 16626 Feb 13 11 :45 shell-survival-quide.md -rw-rw-r-- 1 akira akira 146203 Feb 13 11:35 shell-survival-quide.pdf
This is a very typical situation: if you add special modifiers (keys, options, parameters) to a command call, the behavior of the command changes. Compare: tree / and tree -d / , hostname and hostname -f .

In addition, commands can take file names, directory names, or simply text strings. Try:

Ls -ld /home ls -l /home grep root /etc/passwd

man

man - Help with the commands and programs available on your machine, as well as system calls and the standard C library.

Try: man grep, man atoi, man chdir, man man.

Scrolling forward and backward is done using the “up”, “down”, “PageUp”, “PageDown” buttons; exiting the help view is done with the q button. Search specific text in the help article: press / (forward slash), enter text to search, press Enter. Move to next occurrences - key n.

All help articles are divided into categories. Most important:

It is necessary to indicate from which category the certificate should be shown in cases of coincidence of names. For example, man 3 printf describes a function from the C standard library, and man 1 printf describes console program with the same name.

You can view a list of all help articles available on your machine using the man -k command. (the dot is also part of the komada).

less

When in a small terminal window you need to view very long text(the contents of some file, a long man, etc.), they use special “pager” programs (from the word page, that is, page flippers). The most popular scroller is less, and it is what provides you with the scrolling when you read man pages.

Try and compare the behavior:

Cat /etc/bash.bashrc cat /etc/bash.bashrc |less

You can transfer the file to the pager directly in the parameters:

Less /etc/bash.bashrc

Scrolling up and down - buttons "up", "down", "PageUp", "PageDown", exit - button q. Search for specific text: press / (forward slash), enter the text to search, press Enter. Move to next occurrences - key n. (Do you recognize the instructions about man ? No wonder, less is also used to display help.)

Rights

Any file or directory has a set of “rights” associated with it: the right to read the file, the right to write to the file, the right to execute the file. All users are divided into three categories: file owner, file owner group, all other users.

You can view file permissions using ls -l . For example:

> ls -l Makefile -rw-r--r-- 1 akira students 198 Feb 13 11:48 Makefile
This output means that the owner (akira) can read and write the file, the group (students) can only read, and all other users can also only read.

If you receive a permission denied message while working, this means that you do not have sufficient permissions for the object you wanted to work with.

Read more in man chmod.

STDIN, STDOUT, conveyors (pipes)

There are 3 standard data streams associated with each executing program: input data stream STDIN, output data stream STDOUT, error output stream STDERR.

Run the wc program, enter the text Good day today, press Enter, enter the text good day, press Enter, press Ctrl+d. The wc program will show statistics on the number of letters, words and lines in your text and end:

> wc good day today good day 2 5 24
In this case, you supplied a two-line text to the program's STDIN, and received three numbers in STDOUT.

Now run the command head -n3 /etc/passwd , it should look something like this:

> head -n3 /etc/passwd root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x: 2:2:bin:/bin:/usr/sbin/nologin
In this case, the head program did not read anything from STDIN, but wrote three lines to STDOUT.

You can imagine it this way: the program is a pipe into which STDIN flows and STDOUT flows out.

The most important property The Unix command line is that “pipe” programs can be connected to each other: the output (STDOUT) of one program can be transferred as input data (STDIN) to another program.

Such a construction of connected programs is called a pipe in English, or a conveyor or pipe in Russian.

Combining programs into a pipeline is done with the symbol | (vertical bar)

Run the command head -n3 /etc/passwd |wc , it will look something like this:

> head -n3 /etc/passwd |wc 3 3 117
Here's what happened: the head program output three lines of text in STDOUT, which immediately went to the input of the wc program, which in turn counted the number of characters, words and lines in the resulting text.

You can combine as many programs as you like into a pipeline. For example, you can add another wc program to the previous pipeline, which will count how many words and letters were in the output of the first wc:

> head -n3 /etc/passwd |wc |wc 1 3 24

Creating pipelines (pipes) is a very common task when working on the command line. For an example of how this is done in practice, read the section “Creating a one-liner pipeline.”

I/O redirection

The output (STDOUT) of a program can not only be transferred to another program via a pipeline, but also simply written to a file. This redirection is done using > (greater than sign):

Date > /tmp/today.txt
As a result of executing this command, the file /tmp/today.txt will appear on the disk. View its contents using cat /tmp/today.txt

If a file with the same name already existed, its old contents will be destroyed. If the file did not exist, it will be created. The directory in which the file is created must exist before the command is executed.

If you don't want to overwrite a file, but rather add output to the end, use >> :

Date >> /tmp/today.txt
Check what is now written in the file.

In addition, you can pass any file to the program instead of STDIN. Try:

Wc

What to do when something is unclear

If you encounter system behavior that you don’t understand, or want to achieve a certain result, but don’t know exactly how, I advise you to proceed in the following order (by the way, this applies not only to shells):
  • As clearly as possible, formulate the question or task - there is nothing more difficult than solving “something I don’t know what”;
  • remember if you have already encountered the same or similar problem - in this case, it is worth trying the solution that worked last time;
  • read the appropriate man pages (if you understand which man pages are suitable in your case) - perhaps you will find suitable examples of using commands, the necessary options or links to other commands;
  • think: is it possible to change the task a little? - perhaps, by slightly changing the conditions, you will get a problem that you already know how to solve;
  • ask your clearly formulated question in a search engine - perhaps the answer can be found on Stack Overflow or other sites;
If none of the above helps, seek advice from a teacher, an experienced colleague or friend. And don’t be afraid to ask “stupid” questions - it’s not a shame not to know, it’s a shame not to ask.

If you solve a difficult problem (on your own, with the help of the Internet or other people), write down your solution in case the same problem arises again for you or your friends. You can record it in a simple text file, in Evernote, or publish it on social networks.

Working methods

Copy-and-paste- from man pages, from articles on StackOverflow, etc. The command line consists of text, take advantage of this: copy and use example commands, write down successful findings as a keepsake, publish them on Twitter and blogs.

Pull the previous command from the history, add another command to the pipeline, run, repeat.Cm. See also the section “Creating a one-liner pipeline”.

Basic commands

  • change to another directory: cd ;
  • viewing the contents of files: cat, less, head, tail;
  • file manipulation: cp, mv, rm;
  • viewing directory contents: ls , ls -l , ls -lS ;
  • directory structure: tree , tree -d (you can pass directory as a parameter);
  • search for files: find . -name ... ;

Analytics

  • wc, wc -l;
  • sort -k - sort by the specified field;
  • sort -n - numeric sorting;
  • diff - file comparison;
  • grep , grep -v , grep -w , grep "\ " , grep -E - search for text;
  • uniq , uniq -c - string uniqueization;
  • awk - in the awk "(print $1)" option, to leave only the first field from each line, $1 can be changed to $2, $3, etc.;

System diagnostics

  • ps axuww - information about processes (running programs) running on the machine;
  • top - interactive viewing of the most resource-intensive processes;
  • df - used and free disk space;
  • du - total size of files in the directory (recursively with subdirectories);
  • strace , ktrace - what system calls the process makes;
  • lsof - what files the process uses;
  • netstat -na, netstat -nap - which ports and sockets are open in the system.

You may not have some programs; they need to be installed additionally. In addition, some options of these programs are available only to privileged users (root).

Bulk and semi-automatic execution

At first, skip this section; you will need these commands and constructs when you get to simple shell scripting.
  • test - checking conditions;
  • while read - loop line by line STDIN ;
  • xargs - substitution of strings from STDIN into parameters of the specified program;
  • seq - generation of sequences of natural numbers;
  • () - combine the output of several commands;
  • ; - do one thing after another;
  • && - execute if the first command completes successfully;
  • || - execute if the first command fails;
  • tee - duplicate the program output to STDOUT and to a file on disk.

Miscellaneous

  • date - current date;
  • curl - downloads a document from the specified url and writes the result to STDOUT;
  • touch - update file modification date;
  • kill - send a signal to the process;
  • true - does nothing, returns true, useful for organizing eternal loops;
  • sudo - execute the command as root "a.

Creating a one-liner pipeline

Let's look at an example of a real task: we need to kill all task-6-server processes running as the current user.

Step 1.
Understand which program produces approximately the necessary data, even if not in its pure form. For our task, it is worth getting a list of all processes in the system: ps axuww. Launch.

Step 2.
Look at the data received with your eyes, come up with a filter that will throw out some of the unnecessary data. This is often grep or grep -v . Use the “Up” key to pull out the previous command from the history, assign an invented filter to it, and run it.

Ps axuww |grep `whoami`
- only processes of the current user.

Step 3.
Repeat step 2 until you get the clean data you need.

"
- all processes with the required name (plus, perhaps, extra ones like vim task-6-server.c, etc.),

Ps axuww |grep `whoami` | grep "\ " | grep -v vim ps axuww |grep `whoami` | grep "\ " | grep -v vim |grep -v less
- only processes with the required name

Ps axuww |grep `whoami` | grep "\ " | grep -v vim |grep -v less |awk "(print $2)"

Pids of the required processes, step 3 completed

Step 4.
Apply a suitable final handler. Using the “Up” key, we pull out the previous command from the history and add processing that will complete the solution to the problem:

  • |wc -l to count the number of processes;
  • >pids to write pids to a file;
  • |xargs kill -9 kill processes.

Training tasks

Want to practice new skills? Try the following tasks:
  • get a list of all files and directories in your home directory;
  • get a list of all man articles from category 2 (system calls);
  • count how many times the word grep appears in the grep program man page;
  • count how many processes are currently running as root;
  • find which command appears in the maximum number of help categories (man);
  • count how many times the word var appears on the page ya.ru.
Hint: you will need find , grep -o , awk "(print $1)" , regular expressions in grep , curl -s .

What to study next?

If you start to like the command line, don't stop, keep improving your skills.

Here are some programs that will definitely come in handy if you live on the command line:

  • find with complex options
  • apropos
  • locate
  • telnet
  • netcat
  • tcpdump
  • rsync
  • screen
  • zgrep, zless
  • visudo
  • crontab -e
  • sendmail
In addition, over time it is worth mastering some kind of scripting language, such as perl or python, or even both of them.

Who needs this?

Is it even worth learning the command line and shell scripting today? Definitely worth it. I’ll give just a few examples of Facebook’s requirements for candidates who want to get a job at FB.