Не один год работая с Python и bash я, главным образом, использовал
- первый — для написания программ,
- второй — для выполнения команд ОС.
При этом моя работа в интерактивном режиме Python сводилась к маленьким исследованиям того, как работает некий фрагмент кода. А в командной строке bash я не пользовался конструкциями, присущими языкам программирования, такими, как if
или for
, ограничиваясь запуском отдельных команд.
Но в один прекрасный день 1 час параллельных импровизаций в bash и Python позволили на опыте (а не теоретически) узнать, что
- bash — язык программирования, а не только интерпретатор командной строки, и
- python — полноценная интерактивная рабочая среда!
Желающим получить аналогичное просветление предлагаю поимпровизировать на следующие темы в двух средах. Действительно, все познается в сравнении.
hello world
$ echo Hello world
Hello world
>>> print 'Hello world'
Hello world
Запуск скриптов
Создадим shell и Python скрипты:
$ cat > script.sh
echo Hello world
$ cat > script.py
print 'Hello world'
Запустим их:
$ bash script.sh
Hello world
$ python script.py
Hello world
Переменные
$ x=15
$ echo $x
15
>>> x=15
>>> print x
15
Выражения
$ echo x + 3 = $[ x + 3 ]
x + 3 = 18
$ echo 14 o'clock is $(( 14%12 )) PM
14 o'clock is 2 PM
>>> print 'x + 3 = ' + str(x + 3)
x + 3 = 18
>>> print "14 o'clock is %d PM" % (14 % 12)
14 o'clock is 2 PM
Функции
$ hi() {
> echo hello
> }
$ hi
hello
$ aloha() {
> echo Aloha $1
> }
$ aloha
Aloha
$ aloha Andrey
Aloha Andrey
>>> def hi():
... print 'hello'
...
>>> hi()
hello
>>> def aloha(name=''):
... print 'Aloha', name
...
>>> aloha()
Aloha
>>> aloha('Andrey')
Aloha Andrey
Библиотеки функций
Создадим библиотеки функций (с одной функцией):
$ cat > mylib.sh
helloworld() {
echo Hello, world!
}
^D
$ cat > mylib.py
def helloworld():
print ‘Hello, world!’
^D
Воспользуемся функциями из библиотек:
$ helloworld
-bash: helloworld: command not found
$ source mylib.sh
$ helloworld
Hello, world!
>>> helloworld()
Traceback (most recent call last):
File "", line 1, in ?
NameError: name 'helloworld' is not defined
>>> from mylib import *
>>> helloworld()
Hello, world!
Переменные окружения
Для bash все переменные — переменные окружения (environment variables), а окружение и есть контекст выполнения команд bash.
$ echo My shell is $SHELL
My shell is /bin/bash
>>> import os
>>> print os.environ['SHELL']
/bin/bash
Интерактивная справка
$ man echo
...
q
$ info echo
...
q
Посмотрим справку Python для класcа list
и модуля math
.
>>> help('list')
...
q
>>> help('math')
...
q
Выполнение команд ОС
$ echo Hello world
Hello world
$ echo $?
0
$ ls nosuchfile
ls: nosuchfile: No such file or directory
$ echo $?
2
>>> import os
>>> exitcode = os.system('echo Hello world')
Hello world
>>> print exitcode
0
>>> print os.system('ls nosuchfile')
ls: nosuchfile: No such file or directory
512
Условное выполнение
$ if [ 0 ]
> then
> echo Truth
> else
> echo False
> fi
Truth
>>> if 0:
... print 'Truth'
... else:
... print 'False'
...
False
Конструкция if
в bash работает не только с [ проверкой ]
, но и с любой командой ОС. Поскольку в Unix программы возвращают 0, если выполнение успешно, то bash интерпретирует 0 как истину, а отличное от 0 значение — как ложь.
$ if grep -q "llo, world" mylib.sh
> then
> echo $? : found
> else
> echo $? : not found
> fi
0 : found
Циклы
$ for n in 1 2 3; do echo $(( n*n )); done
1
4
9
$ for x in {3..5} {k..m}; do echo $x; done
3
4
5
k
l
m
$ for i in `seq 3` `seq 10 12`
> do
> echo $i
> done
1
2
3
10
11
12
>>> for n in 1, 2, 3:
... print n*n
...
1
4
9
>>> for x in range(3, 6) + ['k', 'l', 'm']:
... print x
...
3
4
5
k
l
m
>>> for i in range(1, 4) + range(10, 13):
... print i
...
1
2
3
10
11
12
$ for file in `ls`; do echo $file; done
a
abc.txt
...
words
writelog
$ for file in [qf]*; do ls -l $file; done
-rw-rw-r— 1 ay ay 15 Aug 22 11:10 file1.txt
-rw-rw-r— 1 ay ay 28 Aug 22 11:12 file2.txt
-rw-rw-r— 1 ay ay 0 Apr 29 11:40 q.txt
-rw-rw-r— 1 ay ay 13 Jun 21 16:54 qwerty
-rw-rw-r— 1 ay ay 0 Apr 29 11:40 qwerty.txt
>>> import glob
>>> print glob.glob('*')
['ls1.txt', 'hello', ..., 'params.sh', 'writelog']
>>> print glob.glob(‘[qf]*’)
[‘file2.txt’, ‘qwerty.txt’, ‘q.txt’, ‘file1.txt&# 39;, ‘qwerty’]
Чтение стандартного входного потока
$ read answer
yes
$ echo $answer
yes
$ read -p "your name? " name
your name? Andrey
$ echo $name
Andrey
>>> x = raw_input()
qwerty
>>> print x
qwerty
>>> name = raw_input("your name? ")
your name? Andrey
>>> print name
Andrey
В bash, если переменная для вводимого значения явно не задана, значение сохраняется в специальной переменной REPLY
:
$ read
qwerty
$ echo $REPLY
qwerty
Запись и чтение файла
$ cat > file1.txt
hello
good bye
$ cat file1.txt
hello
good bye
>>> with open('file2.txt', 'w') as f:
... f.write("""salut
... see you later
... mata ne""")
...
>>> with open('file2.txt') as f:
... print f.read()
...
salut
see you later
mata ne
Конструкция with
поддерживается в Python начиная с версии 2.5. Для Python версий 2.4 и более ранних необходимо явно закрывать файл, закончив работу с ним:
>>> f = open('mylib.sh', 'w')
>>> f.write("""salut
... see you later
... mata ne""")
>>> f.close()
>>> f = open('mylib.sh')
>>> print f.read()
>>> f.close()
salut
see you later
mata ne
Моему индивидуальному просветлению сильно способствовала книга Advanced Bash-Scripting Guide by Mendel Cooper (а здесь по-русски).