Another adventure
UNIX
Two quick terms:
Fred Brooks, The Mythical Man-Month
$ for host in app db www
> do ssh $host sudo apt-get upgrade
> done
$ head -2 /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
$ sed 's/:.*//' /etc/passwd | head -2
root
daemon
$ sed 's/:.*//' /etc/passwd | sort | head -2
_apt
avahi
>>> lines = open('/etc/passwd').readlines()
>>> line = lines[0]
>>> line
'root:x:0:0:root:/root:bash\n'
>>> line.split()
['root:x:0:0:root:/root:bash']
>>> line.split(':')
['root', 'x', '0', '0', 'root', '/root', 'bash\n']
>>> line.split(':')[0]
'root'
>>> sorted(line.split(':')[0] for line in lines)
['_apt', 'avahi', 'avahi-autoipd', 'backup',...]
✔ Interactivity
MULTICS
MULTICS
“Hierarchical filesystem”
/
├── bin
├── dev
├── etc
└── usr
├── brandon
└── jackie
[('USD', '$', 1.00),
('GBP', '£', 1.32)]
{'.py': ['mod.py', 'test.py'],
'.pyc': ['mod.pyc']}
{('python.org', 80): 9173,
('python.org', 443): 137574}
✔ Recursive Data Layout
ASCII characters 32–126
!"#$%&'()*+,-./0123456789:;<=>?
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
`abcdefghijklmnopqrstuvwxyz{|}
plus the newline \n
README
setup.py
Python-1.5.1.tar.gz
/usr/lib/python2.7
Craziness
/etc/passwd
/etc/passwd
/etc/passwd
Plain text!
root:bh0ENureqXWho.:0:0:root:/:bash
bin:x:1:1:bin:/bin:nologin
sys:x:2:2:sys:/dev:nologin
sshd:x:122:65534::/var/run/sshd:nologin
brandon:Ep6mckrOLChF.:1000:1000:/usr/brandon:zsh
Craziness
UNIX was an act of divestiture
$ grep '^uucp:' /etc/passwd
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
$ sed 's/:.*//' /etc/passwd | sort | head -2
_apt
avahi
Personal preferences
$ set
EDITOR=emacs
HOME=/home/brandon
LOGNAME=brandon
PAGER=less
PYTHONDONTWRITEBYTECODE=PLEASE
SHELL=/bin/zsh
>>> type(sys.argv)
<type 'list'>
>>> type(sys.path)
<type 'list'>
>>> type(sys.modules)
<type 'dict'>
Regular file
Directory
open() read() close()
$ od -x /bin/cat | head -1
0000000 457f 464c 0102 0001 0000 0000 0000 0000
/etc/magic
$ file /etc/passwd
/etc/passwd: ASCII text
$ file Gentium-R.ttf
Gentium-R.ttf: TrueType font data
$ file /bin/ls
/bin/ls: ELF 64-bit LSB executable, x86-64...
$ tty
/dev/pts/1
$ ls -l /dev/pts/1
crw--w---- 1 brandon tty 136, 1 /dev/pts/1
fsck
fsck
Everything is an object
↓
Duck typing
A beautiful error
>>> from collections import namedtuple
>>> Point = namedtuple('Point', 'x y')
>>> p = Point(3.0, 4.0)
>>> isinstance(p, namedtuple)
$ ls /var/tmp
$ echo $?
0
$ ls /etcc
ls: cannot access '/etcc'
$ echo $?
2
if grep brandon /etc/passwd
then
echo "We have a brandon!"
else
echo "We have none."
fi
or
set -e inside the script
$ ls -l passwd grouppw shadow
ls: cannot access 'grouppw': No such file
-rw-r--r-- 1 root root 2225 Sep 11 05:06 passwd
-rw-r----- 1 root shadow 1246 Sep 7 10:44 shadow
$ ls -l passwd grouppw shadow 1>out 2>err
$ cat out
-rw-r--r-- 1 root root 2225 Sep 11 05:06 passwd
-rw-r----- 1 root shadow 1246 Sep 7 10:44 shadow
$ cat err
ls: cannot access 'grouppw': No such file
with open('/etc/password') as f:
lines = list(f)
→ IOError: No such file or directory
try:
f = open(path)
except IOError as e:
print e.errno
print e.filename
print e.strerror
✔ First-Class Errors
$ sed 's/:.*//' /etc/passwd | sort | head -2
$ sed 's/:.*//' /etc/passwd | sort | head -2
lines = open('/etc/passwd')
usernames = (s.split(':')[0] for s in lines)
print sorted(usernames)[:2]
✔ Pipes
✔ Power Tools
$ echo Brandon > my_name
$ ls -l
-rw-r----- 1 ... my_name
$ ln my_name moniker
$ ls -l
-rw-r----- 2 ... my_name
-rw-r----- 2 ... moniker
┌────────────────────────┐
│ RAM │
│ │
│ inode ← PID 1 │
│ nlink=4 ← PID 2 │
└────── ║ ─────────────┘
┌────── ║ ─────────────┐
│ inode ← name1 │
│ nlink=2 ← name2 │
│ │
│ Disk │
└────────────────────────┘
┌────────────────────────┐
│ RAM │
│ │
│ inode ← PID 1 │
│ nlink=3 ← PID 2 │
└────── ║ ─────────────┘
┌────── ║ ─────────────┐
│ inode ← name1 │
│ nlink=1 │
│ │
│ Disk │
└────────────────────────┘
┌────────────────────────┐
│ RAM │
│ │
│ inode ← PID 1 │
│ nlink=2 ← PID 2 │
└────── ║ ─────────────┘
┌────── ║ ─────────────┐
│ inode │
│ nlink=0 │
│ │
│ Disk │
└────────────────────────┘
import os
with open('file', 'w+') as f:
os.unlink('file') # "rm file"!
f.write('one line\n')
f.seek(0)
print f.read() #=> "one line"
$ lsof -p 24751
COMMAND PID FD SIZE/OFF NAME
python 24751 cwd 4096 /home/brandon/talks
python 24751 rtd 4096 /
python 24751 txt 3546104 /usr/bin/python2.7
...
python 24751 0u 0t0 /dev/pts/7
python 24751 1u 0t0 /dev/pts/7
python 24751 2u 0t0 /dev/pts/7
python 24751 3u 9 file (deleted)
stat = os.fstat(f.fileno())
print stat.st_nlink #=> 0
from tempfile import TemporaryFile
✔ Reference Counting
1958 consent decree