# Решения

### 1.
Напишите .sh скрипт в котором в переменную date присваивается значение текущей даты, в переменную claim - строка "snow is white". После вызова скрипт должен выводить строку, используя переменные date и claim:
```
Ср 14 сен 2022 14:50:46 +04: The claim that “snow is white” is true if and only if snow is white.
```
Сделайте файл исполняемым для владельца и вызовите указанием полного или относительного пути к нему.

содержимое скрипта 1.sh
```
date=$(date)
claim='snow is white'
echo "$date: The claim that \"$claim\" is true if and only if $claim."
```

### 2.
Напишите функцию в скрипте, которая создает каталог, путь к которому передан в качестве первого аргумента и переходит в него. Проверьте работу функции в этом же файле. Работает ли функция за пределами контекста скрипта?
```bash
$ cat 2.sh 
mkdir_cd () {
        mkdir -p $1
        cd $1
        echo current dir: $(pwd)
}

mkdir_cd $1
stud@stud15:~$ ./2.sh /tmp/1/2/3/4/5
current dir: /tmp/1/2/3/4/5
stud@stud15:~$ 
```
После выполнения скрипта текущая директория не изменилась. 
```bash
$ mkdir_cd () {
        mkdir -p $1
        cd $1
        echo current dir: $(pwd)
}
stud@stud15:~$ mkdir_cd /tmp/a/b/c/d
current dir: /tmp/a/b/c/d
stud@stud15:/tmp/a/b/c/d$ 
```
После определения функции и вызова в оболочке изменилась.


### 3.
Менее известной, но полезной может быть подстановка дескриптора файла с результатом выполнения команды. `<( CMD )` выполнит `CMD` и поместит вывод во временный файл и заменит `<()` именем этого файла. Это полезно, когда команды ожидают, что значения будут переданы через файл, а не STDIN. Например, `diff <(ls foo) <(ls bar)` покажет различия между файлами в каталогах foo и bar.
```
$ diff <(cat buylist) <(cat bought)
1,3c1,5
< salad
< milk
< bread
---
> icecream
> cheese
> cake
> lays
> beer
```

### 4.
Попробуйте условные выражения в скрипте в if конструкции:
```bash
$ cat 4.sh 
if [[ true && true ]]
then
        echo "True"
fi

if [[ true || false ]]
then
        echo "True"
fi
stud@stud15:~$ ./4.sh 
True
True
```

### 5.
Напишите скрипт, который проходит по всем файлам, переданным в качестве аргументов, и ищет в них строку hello. Перенаправьте grep `STDOUT` и `STDERR` в специальный файл `/dev/null`. Для каждого файла в if создайте файл с содержимым `hello`, если `grep` завершился с ошибкой.  
```bash
$ cat 5.sh 
for f in $@; do
        grep hello $f 2> /dev/null 1> /dev/null
        if [[ $? -ne 0 ]]
        then
                echo "hello" > $f
        fi
$ ./5.sh /tmp/one /tmp/two /tmp/three
/tmp/one has no hello in it. correcting.
/tmp/two has no hello in it. correcting.
/tmp/three has no hello in it. correcting.
$ grep hello /tmp/* 2> /dev/null 
/tmp/one:hello
/tmp/three:hello
/tmp/two:hello
```

### 6.
Установите пакет shellcheck и проверьте написанный вами ранее скрипт одноименной командой.
```bash
$ shellcheck 5.sh 

In 5.sh line 1:
for f in $@; do
^-- SC2148 (error): Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.
         ^-- SC2068 (error): Double quote array expansions to avoid re-splitting elements.


In 5.sh line 2:
        grep hello $f 2> /dev/null 1> /dev/null
                   ^-- SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean: 
        grep hello "$f" 2> /dev/null 1> /dev/null


In 5.sh line 3:
        if [[ $? -ne 0 ]]
              ^-- SC2181 (style): Check exit code directly with e.g. 'if ! mycmd;', not indirectly with $?.


In 5.sh line 5:
                echo $f has no hello in it. correcting.
                     ^-- SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean: 
                echo "$f" has no hello in it. correcting.


In 5.sh line 6:
                echo "hello" > $f
                               ^-- SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean: 
                echo "hello" > "$f"

For more information:
  https://www.shellcheck.net/wiki/SC2068 -- Double quote array expansions to ...
  https://www.shellcheck.net/wiki/SC2148 -- Tips depend on target shell and y...
  https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
```

### 7.
Напишите скрипт, который выполняет следующий код:
```bash
$ cat ./7.sh 
#!/usr/bin/env python
import sys
for arg in reversed(sys.argv[1:]):
        print(arg)
$ ./7.sh 1 2 3 4 5
5
4
3
2
1
```

### 8.
Функции выполняются в текущей среде оболочке, тогда как скрипты выполняются в своем собственном процессе. 

Проверьте, что функции могут изменять переменные среды, например, изменить текущий каталог, тогда как скрипт не может. Напишите скрипт, в котором инициализируются две переменные `A` и `B`. Перед одной из них указывается `export `. Выполните скрипт и посмотрите на выдачу команды `env`. Выполните файл командой source (source --help). Какие переменные экспортировались в оболочку? 
```bash
$ cat 8.sh 
#!/bin/bash
A=1
export B=2
stud@stud15:~$ ./8.sh 
stud@stud15:~$ env | grep -E "^A|B"
stud@stud15:~$ source ./8.sh 
stud@stud15:~$ env | grep -E "^A|B"
B=2
```

### 9.
Напишите сценарий bash, который запускает следующий сценарий до тех пор, пока он не завершится аварийно, записывает стандартный вывод и потоки ошибок в файлы и печатает все в конце. 
```bash
stud@stud15:~$ cat random_bug_script.sh 
#!/usr/bin/env bash

n=$(( RANDOM % 100 ))
echo $n
if [[ n -eq 42 ]]; then
  echo "Something went wrong"
  >&2 echo "The error was using magic numbers"
  exit 1
fi

echo "Everything went according to plan"

stud@stud15:~$ cat repeat_until_error.sh
#!/bin/bash
echo "" > output.log
echo "" > error.log
i=0
while true; do
  bash $1 2>> error.log 1>> output.log
  if [[ $? -ne 0 ]]; then
        echo Took "$i" iterations to get an error.
        echo "\noutput.log"
        cat output.log
        echo "\nerror.log"
        cat error.log
        break
  fi
  i=$((i+1))
done

stud@stud15:~$ ./repeat_until_error.sh ./random_bug_script.sh 
Took 37 iterations to get an error.

output.log

Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Everything went according to plan
Something went wrong

error.log

The error was using magic numbers
```

Бонусный балл, за то, что вы можете сообщить, сколько запусков потребовалось для сбоя сценария.
```bash
stud@stud15:~$ cat mean.sh 
#!/bin/bash
script=$1
iters=$2
sum=0
for i in $(seq $iters)
do
        failedoniter=$(bash $script | grep 'Took' | awk '{ print $2; }')
        sum=$((sum+failedoniter))
done

echo Done $iters trials.
echo Mean number of steps until error: $(( sum / iters ))

$ time ./mean.sh "./repeat_until_error.sh ./random_bug_script.sh" 1000
Done 1000 trials.
Mean number of steps until error: 99

real    2m6,924s
user    1m36,964s
sys     0m29,409s
```

### 10.
Напишите скрипт, который: 
- создаёт пользователя на двух машинах,
- кроме домашней директории заводит папку для пользователя в `/ceph/` с нужными правами, 
- создаёт ссылку в домашней директории на директорию в `/ceph/`, 
- ограничивает доступ к домашней папке всем, кроме владельца, 
- генерирует пользователям ключи ed25519, рассылает по машинам и регистрирует ключи для беспарольного перемещения пользователя между машинами. 

Настройка беспарольного перехода для суперпользователя между машинами
```
root@stud15:~# cat .ssh/config 
Host w001
        HostName 10.160.179.25

Host w002
        HostName 10.160.179.55

root@stud15:~# hostname -i
10.160.179.25
root@stud15-v1:~# hostname -i
10.160.179.55

root@stud15-v1:~# cat /etc/ssh/sshd_config | grep PermitRootLogin 
PermitRootLogin yes

root@stud15-v1:~# systemctl restart sshd

root@stud15:~# ssh-copy-id w002
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@10.160.179.55's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'w002'"
and check to make sure that only the key(s) you wanted were added.

root@stud15-v1:~# cat /etc/ssh/sshd_config | grep PermitRootLogin 
PermitRootLogin prohibit-password

root@stud15-v1:~# systemctl restart sshd

root@stud15:~# ssh-copy-id w001
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '10.160.179.25 (10.160.179.25)' can't be established.
ECDSA key fingerprint is SHA256:3K1vZ3p2zlZpJabnqm3ZqwUPkmxxnIHiqYplqRLEku8.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed

/usr/bin/ssh-copy-id: WARNING: All keys were skipped because they already exist on the remote system.
                (if you think this is a mistake, you may want to use -f option)
```
Скрипт 
```bash
root@stud15:~# cat create_user.sh 
#!/bin/bash

help() {
        echo "Usage: ./create_user.sh file_with_node_ip_addresses user_name"
}

if [[ $# < 2 ]]
then
        help
        exit
fi


nodes=$(cat $1)
user=$2
create_user_and_link_command="useradd $user --create-home --shell=/bin/bash --key HOME_MODE=0700; \
mkdir -p /ceph/$user -m 0700; \
chown $user:$user /ceph/$user; \
ln -s /ceph/$user /home/$user/ceph; \
chown $user:$user --no-dereference /home/$user/ceph"

mkdir -p /root/users.ssh/$user/
ssh-keygen -t ed25519 -N ""  -f "/root/users.ssh/$user/id_ed25519"
sed --in-place "s/root/user/" "/root/users.ssh/$user/id_ed25519.pub"
cat /root/users.ssh/$user/id_ed25519.pub > /root/users.ssh/$user/authorized_keys

echo "" > /root/users.ssh/$user/known_hosts
for node in $nodes; do
  ssh-keyscan -H "$node" >> /root/users.ssh/$user/known_hosts
done
 
for node in $nodes; do
  echo "$node" "$create_user_and_link_command"
  ssh "$node" "$create_user_and_link_command"
  scp -r /root/users.ssh/$user/ $node:/home/$user/.ssh
  ssh "$node" "chown -R $user:$user /home/$user/.ssh && chmod 0700 /home/$user/.ssh/"
done

root@stud15:~# cat nodes
10.160.179.25
10.160.179.55
```

Проверка
```
root@stud15:~# ./create_user.sh nodes user6
Generating public/private ed25519 key pair.
Your identification has been saved in /root/users.ssh/user6/id_ed25519
Your public key has been saved in /root/users.ssh/user6/id_ed25519.pub
The key fingerprint is:
SHA256:FdusRTajDoM/7us/Tyf3VCmu/8kAWjWoYkerUGKggzg root@stud15
The key's randomart image is:
+--[ED25519 256]--+
|   .      . =    |
|o . .  .   O.o   |
|Eo   o..o.+.+o   |
| .. . o..=oo. . .|
|     . oS+oo . ..|
|      o.+.o o . .|
|       ...  ooo .|
|       .  ...+oo.|
|       .+o.+o..+.|
+----[SHA256]-----+
# 10.160.179.25:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
# 10.160.179.25:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
# 10.160.179.25:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
# 10.160.179.25:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
# 10.160.179.25:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
# 10.160.179.55:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
# 10.160.179.55:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
# 10.160.179.55:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
# 10.160.179.55:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
# 10.160.179.55:22 SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u1
10.160.179.25 useradd user6 --create-home --shell=/bin/bash --key HOME_MODE=0700; mkdir -p /ceph/user6 -m 0700; chown user6:user6 /ceph/user6; ln -s /ceph/user6 /home/user6/ceph; chown user6:user6 --no-dereference /home/user6/ceph
id_ed25519.pub                                                                                                   100%   93   484.7KB/s   00:00    
id_ed25519                                                                                                       100%  399     2.8MB/s   00:00    
authorized_keys                                                                                                  100%   93   746.1KB/s   00:00    
known_hosts                                                                                                      100% 1957    12.5MB/s   00:00    
10.160.179.55 useradd user6 --create-home --shell=/bin/bash --key HOME_MODE=0700; mkdir -p /ceph/user6 -m 0700; chown user6:user6 /ceph/user6; ln -s /ceph/user6 /home/user6/ceph; chown user6:user6 --no-dereference /home/user6/ceph
id_ed25519.pub                                                                                                   100%   93   434.1KB/s   00:00    
id_ed25519                                                                                                       100%  399     2.4MB/s   00:00    
authorized_keys                                                                                                  100%   93   625.8KB/s   00:00    
known_hosts                                                                                                      100% 1957    10.4MB/s   00:00    
root@stud15:~# 


user6@stud15:~$ ssh 10.160.179.55
Linux stud15-1v15 5.10.0-17-amd64 #1 SMP Debian 5.10.136-1 (2022-08-13) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
user6@stud15-1v15:~$ ssh 10.160.179.25
Linux stud15 5.10.0-16-amd64 #1 SMP Debian 5.10.127-1 (2022-06-30) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
user6@stud15:~$ 


root@stud15:~# ls -la /home/user6/
total 28
drwx------  3 user6 user6 4096 сен 15 11:49 .
drwxr-xr-x 13 root  root  4096 сен 15 11:47 ..
-rw-------  1 user6 user6   18 сен 15 11:49 .bash_history
-rw-r--r--  1 user6 user6  220 мар 27 22:40 .bash_logout
-rw-r--r--  1 user6 user6 3526 мар 27 22:40 .bashrc
lrwxrwxrwx  1 user6 user6   11 сен 15 11:47 ceph -> /ceph/user6
-rw-r--r--  1 user6 user6  807 мар 27 22:40 .profile
drwx------  2 user6 user6 4096 сен 15 11:47 .ssh
root@stud15:~# ls -la /ceph
total 32
drwxr-xr-x  8 root  root  4096 сен 15 11:47 .
drwxr-xr-x 21 root  root  4096 сен 15 11:12 ..
drwx------  2 user1 user1 4096 сен 15 11:14 user1
drwx------  2 user2 user2 4096 сен 15 11:25 user2
drwx------  2 user3 user3 4096 сен 15 11:38 user3
drwx------  2 user4 user4 4096 сен 15 11:42 user4
drwx------  2 user5 user5 4096 сен 15 11:44 user5
drwx------  2 user6 user6 4096 сен 15 11:47 user6
```