- Глава 7. Проверка условий
- 7.1. Конструкции проверки условий
- 7.3. Операции сравнения
- Условные операторы if..else командной оболочки Bash
- Bash if..else Statement
- В этом руководстве мы познакомим вас с основами if оператора Bash и покажем, как его использовать в сценариях оболочки
- if..else
- if..elif..else
- Вложенные if
- Несколько условий
- Тестовые операторы
- Вывод
- Conditions in bash scripting (if statements)
- Let’s start your cloud journey
- Bash Programming Introduction
- The syntax of an bash if statement
- The basic rules of bash conditions
- Different condition syntaxes
- 1. Single-bracket syntax
- 2. Double-bracket syntax
- 3. Double-parenthesis syntax
- Table of conditions
- 1. File-based conditions:
- 2. String-based conditions:
- 5. Double-parenthesis syntax conditions:
- Diving a little deeper
- Conclusion
Глава 7. Проверка условий
практически любой язык программирования включает в себя условные операторы, предназначенные для проверки условий, чтобы выбрать тот или иной путь развития событий в зависимости от этих условий. В Bash, для проверки условий, имеется команда test, различного вида скобочные операторы и условный оператор if/then.
7.1. Конструкции проверки условий
Оператор if/then проверяет — является ли код завершения списка команд 0 (поскольку 0 означает «успех» ), и если это так, то выполняет одну, или более, команд, следующие за словом then.
Существует специальная команда — [ (левая квадратная скобка). Она является синонимом команды test, и является встроенной командой (т.е. более эффективной, в смысле производительности). Эта команда воспринимает свои аргументы как выражение сравнения или как файловую проверку и возвращает код завершения в соответствии с результатами проверки (0 — истина, 1 — ложь).
Начиная с версии 2.02, Bash предоставляет в распоряжение программиста конструкцию [[ . ]] расширенный вариант команды test , которая выполняет сравнение способом более знакомым программистам, пишущим на других языках программирования. Обратите внимание: [[ — это зарезервированное слово, а не команда.
Bash исполняет [[ $a -lt $b ]] как один элемент, который имеет код возврата.
Круглые скобки (( . )) и предложение let . так же возвращают код 0 , если результатом арифметического выражения является ненулевое значение. Таким образом, арифметические выражения могут учавствовать в операциях сравнения.
Условный оператор if проверяет код завершения любой команды, а не только результат выражения, заключенного в квадратные скобки.
Оператор if/then допускает наличие вложенных проверок.
Это детальное описание конструкции «if-test» любезно предоставлено Stephane Chazelas.
Пример 7-1. Что есть «истина»?
Упражнение. Объясните результаты, полученные в Пример 7-1.
Condition | True if | Example/explanation | |
---|---|---|---|
[ -a existingfile ] | file ‘existingfile’ exists. | if [ -a tmp.tmp ]; thenrm -f tmp.tmp # Make sure we’re not bothered by an old temporary filefi | |
[ -b blockspecialfile ] | file ‘blockspecialfile’ exists and is block special. | Block special files are special kernel files found in /dev, mainly used for ATA devices like hard disks, cd-roms and floppy disks.if [ -b /dev/fd0 ]; thendd if=floppy.img of=/dev/fd0 # Write an image to a floppyfi | |
[ -c characterspecialfile ] | file ‘characterspecialfile’ exists and is character special. | Character special files are special kernel files found in /dev, used for all kinds of purposes (audio hardware, tty’s, but also /dev/null).if [ -c /dev/dsp ]; thencat raw.wav > /dev/dsp # This actually works for certain raw wav filesfi | |
[ -d directory ] | file ‘directory’ exists and is a directory. | In UNIX-style, directories are a special kind of file.if [ -d /.kde ]; thenecho “You seem to be a kde user.”fi | |
[ -e existingfile ] | file ‘existingfile’ exists. | (same as -a, see that entry for an example) | |
[ -f regularfile ] | file ‘regularfile’ exists and is a regular file. | A regular file is neither a block or character special file nor a directory.if [ -f /.bashrcfi | |
[ -g sgidfile ] | file ‘sgidfile’ exists and is set-group-ID. | When the SGID-bit is set on a directory, all files created in that directory will inherit the group of the directory.if [ -g . ]; thenecho “Created files are inheriting the group ‘$(ls -ld . | awk ‘< print $4 >’)’ from the working directory.”fi | |
[ -G fileownedbyeffectivegroup ] | file ‘fileownedbyeffectivegroup’ exists and is owned by the effective group ID. | The effective group id is the primary group id of the executing user.if [ ! -G file ]; then # An exclamation mark inverts the outcome of the condition following itchgrp $(id -g) file # Change the group if it’s not the effective onefi | |
[ -h symboliclink ] | file ‘symboliclink’ exists and is a symbolic link. | if [ -h $pathtofile ]; thenpathtofile=$(readlink -e $pathtofile) # Make sure $pathtofile contains the actual file and not a symlink to itfi | |
[ -k stickyfile ] | file ‘stickyfile’ exists and has its sticky bit set. | The sticky bit has got quite a history, but is now used to prevent world-writable directories from having their contents deletable by anyone.if [ ! -k /tmp ]; then # An exclamation mark inverts the outcome of the condition following itecho “Warning! Anyone can delete and/or rename your files in /tmp!”fi | |
[ -L symboliclink ] | file ‘symboliclink’ exists and is a symbolic link. | (same as -h, see that entry for an example) | |
[ -N modifiedsincelastread ] | file ‘modifiedsincelastread’ exists and was modified after the last read. | if [ -N /etc/crontab ]; thenkillall -HUP crond # SIGHUP makes crond reread all crontabsfi | |
[ -O fileownedbyeffectiveuser ] | file ‘fileownedbyeffectiveuser’ exists and is owned by the user executing the script. | if [ -O file ]; thenchmod 600 file # Makes the file private, which is a bad idea if you don’t own itfi | |
[ -p namedpipe ] | file ‘namedpipe’ exists and is a named pipe. | A named pipe is a file in /dev/fd/ that can be read just once. See my bash tutorial for a case in which it’s used.if [ -p $file ]; thencp $file tmp.tmp # Make sure we’ll be able to readfile=”tmp.tmp” # the file as many times as we likefi | |
[ -r readablefile ] | file ‘readablefile’ exists and is readable to the script. | if [-r file ]; thencontent=$(cat file) # Set $content to the content of the filefi | |
[ -s nonemptyfile ] | file ‘nonemptyfile’ exists and has a size of more than 0 bytes. | if [ -s logfile ]; thengzip logfile # Backup the old logfiletouch logfile # before creating a fresh one.fi | |
[ -S socket ] | file ‘socket’ exists and is a socket. | A socket file is used for inter-process communication, and features an interface similar to a network connection.if [ -S /var/lib/mysql/mysql.sock ]; thenmysql –socket=/var/lib/mysql/mysql.sock # See this MySQL tipfi | |
[ -t openterminal ] | file descriptor ‘openterminal’ exists and refers to an open terminal. | Virtually everything is done using files on Linux/UNIX, and the terminal is no exception.if [ -t /dev/pts/3 ]; thenecho -e “nHello there. Message from terminal $(tty) to you.” > /dev/pts/3 # Anyone using that terminal will actually see this message!fi | |
[ -u suidfile ] | file ‘suidfile’ exists and is set-user-ID. | Setting the suid-bit on a file causes execution of that file to be done with the credentials of the owner of the file, not of the executing user.if [ -u executable ]; thenecho “Running program executable as user $(ls -l executable | awk ‘< print $3 >’).”fi | |
[ -w writeablefile ] | file ‘writeablefile’ exists and is writeable to the script. | if [ -w /dev/hda ]; thengrub-install /dev/hdafi | |
[ -x executablefile ] | file ‘executablefile’ exists and is executable for the script. | Note that the execute permission on a directory means that it’s searchable (you can see which files it contains).if [ -x /root ]; thenecho “You can view the contents of the /root directory.”fi | |
[ newerfile -nt olderfile ] | file ‘newerfile’ was changed more recently than ‘olderfile’, or if ‘newerfile’ exists and ‘olderfile’ doesn’t. | if [ story.txt1 -nt story.txt ]; thenecho “story.txt1 is newer than story.txt; I suggest continuing with the former.”fi | |
[ olderfile -ot newerfile ] | file ‘olderfile’ was changed longer ago than ‘newerfile’, or if ‘newerfile’ exists and ‘olderfile’ doesn’t. | if [ /mnt/remote/remotefile -ot localfile ]; thencp -f localfile /mnt/remote/remotefile # Make sure the remote location has the newest version of the file, toofi | |
[ same -ef file ] | file ‘same’ and file ‘file’ refer to the same device/inode number. | if [ /dev/cdrom -ef /dev/dvd ]; thenecho “Your primary cd drive appears to read dvd’s, too.”fi | |
Condition | True if | Example/explanation | |
[ STRING1 == STRING2 ] | STRING1 is equal to STRING2. | if [ “$1” == “moo” ]; thenecho $cow # Ever tried executing ‘apt-get moo’?fiNote: you can also use a single “=” instead of a double one. | |
[ STRING1 != STRING2 ] | STRING1 is not equal to STRING2. | if [ “$userinput” != “$password” ]; thenecho “Access denied! Wrong password!”exit 1 # Stops script execution right herefi | |
[ STRING1 > STRING2 ] | STRING1 sorts after STRING2 in the current locale (lexographically). | The backslash before the angle bracket is there because the bracket needs to be escaped to be interpreted correctly. As an example we have a basic bubble sort:(Don’t feel ashamed if you don’t understand this, it is a more complex example)array=( linux tutorial blog )swaps=1while (( swaps > 0 )); doswaps=0for (( i=0; i “$ | |
[ STRING1 With the double-parenthesis syntax, you can use the following conditions: 5. Double-parenthesis syntax conditions: | |||
Condition | True if | Example/explanation | |
(( NUM1 == NUM2 )) | NUM1 is equal to NUM2. | These conditions only accept integer numbers. Strings will be converted to integer numbers, if possible. Some random examples:if (( $? == 0 )); then # $? returns the exit status of the previous commandecho “Previous command ran succesfully.”fiif (( $(ps -p $pid -o ni=) != $(nice) )); thenecho “Process $pid is running with a non-default nice value”fiif (( $num NUM2 )) | NUM1 is greater than NUM2. |
(( NUM1 >= NUM2 )) | NUM1 is greater than or equal to NUM2. | ||
(( NUM1 After this dry information load, here’s a bit of explanation for those who want to know more… Diving a little deeperI said I’d tell more about the fact that if essentially checks the exit status of commands. And so I will. The basic rule of bash when it comes to conditions is 0 equals true, >0 equals false.That’s pretty much the opposite of many programming languages where 0 equals false and 1 (or more) equals true. The reason behind this is that shells like bash deal with programs a lot. By UNIX convention, programs use an exit status for indicating whether execution went alright or an error occured. As a succesful execution doesn’t require any explanation, it needs only one exit status. If there was a problem, however, it is useful to know what went wrong. Therefore, 0 is used for a succesful execution, and 1-255 to indicate what kind of error occured. The meaning of the numbers 1-255 differs depending on the program returning them.Anyway, if executes the block after then when the command returns 0. Yes, conditions are commands. The phrase [ $foo -ge 3 ] returns an exit status, and the other two syntaxes as well! Therefore, there’s a neat trick you can use to quickly test a condition: In this example, “echo true” is only executed if “[ $foo -ge 3 ]” returns 0 (true). Why is that, you might ask. It’s because bash only evaluates a condition when needed. When using the and combining expression, both conditions need to be true to make the combining expression return true. If the first condition returns false, it doesn’t matter what the second one returns; the result will be false. Therefore, bash doesn’t evaluate the second condition, and that’s the reason why “echo true” is not executed in the example. This is the same for the or operator (“||”), where the second condition is not evaluated if the first one is true.Well, so much for the diving. If you want to know even more, I’d like to point you to the Advanced Bash-Scripting Guide and maybe the Bash Reference Manual, or even this System Administrator’s Guide to Bash Scripting. ConclusionIn this tutorial, you’ve been able to make a start at understanding the many possibilities of conditions in bash scripting. You’ve been able to read about the basic rules of writing and using conditions, about the three syntaxes and their properties, and maybe you took the opportunity to dive a little deeper. I hope you enjoyed the reading as much as I enjoyed the writing. You can always return here to look up conditions in the table (bookmark that link to see the table directly), or to refresh your knowledge. If you have any suggestions, additions or other feedback, feel free to comment. Thanks for reading and happy scripting! Источник |