This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
средства_программирования_shell [2024/06/19 13:44] val [Отправка email с вложениями] |
средства_программирования_shell [2026/05/12 16:34] (current) val |
||
|---|---|---|---|
| Line 10: | Line 10: | ||
| * [[https://www.tutorialspoint.com/execute_bash_online.php|Execute Bash Shell Online]] | * [[https://www.tutorialspoint.com/execute_bash_online.php|Execute Bash Shell Online]] | ||
| * [[https://www.shellcheck.net/|ShellCheck finds bugs in your shell scripts.]] | * [[https://www.shellcheck.net/|ShellCheck finds bugs in your shell scripts.]] | ||
| + | |||
| + | * [[http://redsymbol.net/articles/unofficial-bash-strict-mode/|Use Bash Strict Mode (Unless You Love Debugging)]] | ||
| ===== Проверка синтаксиса ===== | ===== Проверка синтаксиса ===== | ||
| Line 192: | Line 194: | ||
| <code> | <code> | ||
| - | $ cat log_gen.sh | + | bash -c 'cat <<END >log_gen.sh |
| - | </code><code> | + | |
| while : | while : | ||
| do | do | ||
| Line 199: | Line 200: | ||
| logger -t cisco -p local0.info "Message 2" | logger -t cisco -p local0.info "Message 2" | ||
| done | done | ||
| + | END' | ||
| </code><code> | </code><code> | ||
| - | $ sh cisco_log_gen.sh | + | $ sh log_gen.sh |
| </code> | </code> | ||
| ===== Примеры использования скриптов sh в системах загрузки ===== | ===== Примеры использования скриптов sh в системах загрузки ===== | ||
| Line 394: | Line 396: | ||
| #!/bin/bash | #!/bin/bash | ||
| base=/var/www | base=/var/www | ||
| - | #log=/var/log/webd.log | + | #exec 2>>/var/log/webd.log |
| + | #echo "ARGS: $*" >&2 | ||
| read request | read request | ||
| - | ##echo "$request" >> $log # for educational demonstration | + | ##echo "$request" >&2 # for educational demonstration |
| filename="${request#GET }" | filename="${request#GET }" | ||
| Line 409: | Line 412: | ||
| do | do | ||
| read -r header | read -r header | ||
| - | ## echo "$header" >> $log # for educational demonstration | + | ## echo "$header" >&2 # for educational demonstration |
| [ "$header" == $'\r' ] && break; | [ "$header" == $'\r' ] && break; | ||
| ## [ "$header" == $'' ] && break; # for STDIN/STDOUT educational demonstration | ## [ "$header" == $'' ] && break; # for STDIN/STDOUT educational demonstration | ||
| Line 416: | Line 419: | ||
| if [ -e "$filename" ] | if [ -e "$filename" ] | ||
| then | then | ||
| - | # echo `date` OK $filename on `hostname` >> $log | + | # echo `date` OK $filename on `hostname` >&2 |
| echo -e "HTTP/1.1 200 OK\r" | echo -e "HTTP/1.1 200 OK\r" | ||
| - | echo -e "Content-Type: $(/usr/bin/file -bi $filename)\r" | + | echo -e "Content-Type: $(/usr/bin/file -bi "$filename")\r" |
| echo -e "\r" | echo -e "\r" | ||
| /bin/cat "$filename" | /bin/cat "$filename" | ||
| else | else | ||
| - | # echo "$(date)" ERR $filename on "$(hostname)" >> "$log" | + | # echo "$(date)" ERR "$filename" on "$(hostname)" >&2 |
| echo -e "HTTP/1.1 404 Not Found\r" | echo -e "HTTP/1.1 404 Not Found\r" | ||
| echo -e "Content-Type: text/html;\r" | echo -e "Content-Type: text/html;\r" | ||
| Line 436: | Line 439: | ||
| </code> | </code> | ||
| - | ==== Ресурсы Web сервера на shell ==== | + | === Ресурсы Web сервера на shell === |
| <code> | <code> | ||
| - | # mkdir /var/www | + | # mkdir -p /var/www/img |
| # cat /var/www/index.html | # cat /var/www/index.html | ||
| Line 447: | Line 450: | ||
| </html> | </html> | ||
| </code><code> | </code><code> | ||
| - | # mkdir /var/www/img | + | # wget -O /var/www/img/logo.gif https://val.bmstu.ru/unix/Media/logo.gif |
| - | </code> | + | |
| - | + | ||
| - | <code> | + | |
| - | # wget -O /var/www/img/logo.gif http://val.bmstu.ru/unix/Media/logo.gif | + | |
| </code> | </code> | ||
| * [[Сервис INETD]] | * [[Сервис INETD]] | ||
| - | ==== Проверка ==== | + | * [[Управление сервисами в Linux#Systemd Sockets]] |
| + | === Проверка === | ||
| <code> | <code> | ||
| Line 467: | Line 467: | ||
| ==== Отправка email с вложениями ==== | ==== Отправка email с вложениями ==== | ||
| + | * [[Утилита curl]] | ||
| * [[https://serverfault.com/questions/38919/send-an-email-with-an-attached-file-using-telnet-or-netcat|Send an email with an attached file using telnet or netcat]] | * [[https://serverfault.com/questions/38919/send-an-email-with-an-attached-file-using-telnet-or-netcat|Send an email with an attached file using telnet or netcat]] | ||
| Line 498: | Line 499: | ||
| } | nc $MAILSERVER 25 | } | nc $MAILSERVER 25 | ||
| </code> | </code> | ||
| + | |||
| + | ==== Отправка сообщения на все консоли ==== | ||
| + | <code> | ||
| + | root@server:~# cat /usr/local/bin/mywall.sh | ||
| + | </code><code> | ||
| + | #!/bin/sh | ||
| + | |||
| + | for MY_T in $(w | grep pts | awk '{print $2}') | ||
| + | do | ||
| + | echo "$1" | jq > /dev/$MY_T | ||
| + | done | ||
| + | </code> | ||
| + | ==== Тестирование Web приложения на shell ==== | ||
| + | |||
| + | * На примере [[Web интерфейс к почте#Roundcube]], автор [[https://www.perplexity.ai/]] | ||
| + | <code> | ||
| + | root@server:~# cat /usr/local/bin/roundcube_monitor.sh | ||
| + | </code><code> | ||
| + | #!/usr/bin/env bash | ||
| + | set -euo pipefail | ||
| + | |||
| + | ROUND_URL="${1:-http://server.corp13.un/mail/}" | ||
| + | LOGIN="${2:-student}" | ||
| + | PASSWORD="${3:-password}" | ||
| + | |||
| + | TMP_DIR="$(mktemp -d)" | ||
| + | COOKIE_JAR="$TMP_DIR/cookies.txt" | ||
| + | LOGIN_PAGE="$TMP_DIR/login.html" | ||
| + | RESPONSE_PAGE="$TMP_DIR/response.html" | ||
| + | LOGOUT_PAGE="$TMP_DIR/logout.html" | ||
| + | |||
| + | cleanup() { | ||
| + | rm -rf "$TMP_DIR" | ||
| + | } | ||
| + | trap cleanup EXIT | ||
| + | |||
| + | extract_token() { | ||
| + | local file="$1" | ||
| + | grep -oP 'name="_token"\s+value="\K[^"]+' "$file" | head -n1 || true | ||
| + | } | ||
| + | |||
| + | echo "1) Открываю форму входа: $ROUND_URL" | ||
| + | curl -ksSL \ | ||
| + | -c "$COOKIE_JAR" \ | ||
| + | -b "$COOKIE_JAR" \ | ||
| + | "$ROUND_URL" \ | ||
| + | -o "$LOGIN_PAGE" | ||
| + | |||
| + | TOKEN="$(extract_token "$LOGIN_PAGE")" | ||
| + | |||
| + | if [[ -z "$TOKEN" ]]; then | ||
| + | echo "CRITICAL: не найден _token на странице логина" | ||
| + | exit 2 | ||
| + | fi | ||
| + | |||
| + | echo "2) Найден CSRF token" | ||
| + | |||
| + | echo "3) Отправляю форму логина" | ||
| + | curl -ksSL \ | ||
| + | -c "$COOKIE_JAR" \ | ||
| + | -b "$COOKIE_JAR" \ | ||
| + | -e "$ROUND_URL" \ | ||
| + | -A "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124 Safari/537.36" \ | ||
| + | -H "Content-Type: application/x-www-form-urlencoded" \ | ||
| + | --data-urlencode "_token=$TOKEN" \ | ||
| + | --data-urlencode "_task=login" \ | ||
| + | --data-urlencode "_action=login" \ | ||
| + | --data-urlencode "_timezone=Europe/Moscow" \ | ||
| + | --data-urlencode "_url=" \ | ||
| + | --data-urlencode "_user=$LOGIN" \ | ||
| + | --data-urlencode "_pass=$PASSWORD" \ | ||
| + | "$ROUND_URL?_task=login" \ | ||
| + | -o "$RESPONSE_PAGE" | ||
| + | |||
| + | if grep -qiE 'Invalid request|Invalid security token|request token' "$RESPONSE_PAGE"; then | ||
| + | echo "CRITICAL: ошибка CSRF/token при логине" | ||
| + | exit 2 | ||
| + | fi | ||
| + | |||
| + | if grep -qiE 'login failed|authentication failed|invalid password|failed to login' "$RESPONSE_PAGE"; then | ||
| + | echo "CRITICAL: логин не выполнен" | ||
| + | exit 2 | ||
| + | fi | ||
| + | |||
| + | if grep -qi '_task=mail' "$RESPONSE_PAGE" || grep -qi 'logout' "$RESPONSE_PAGE"; then | ||
| + | echo "OK: вход в Roundcube выполнен" | ||
| + | else | ||
| + | echo "WARNING: результат логина неоднозначен" | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | echo "4) Выполняю logout" | ||
| + | |||
| + | POST_LOGIN_TOKEN="$(extract_token "$RESPONSE_PAGE")" | ||
| + | if [[ -z "$POST_LOGIN_TOKEN" ]]; then | ||
| + | POST_LOGIN_TOKEN="$TOKEN" | ||
| + | fi | ||
| + | |||
| + | curl -ksSL \ | ||
| + | -c "$COOKIE_JAR" \ | ||
| + | -b "$COOKIE_JAR" \ | ||
| + | -e "$ROUND_URL?_task=mail" \ | ||
| + | "$ROUND_URL?_task=logout&_token=$POST_LOGIN_TOKEN" \ | ||
| + | -o "$LOGOUT_PAGE" | ||
| + | |||
| + | if grep -qiE 'request check failed|invalid security token' "$LOGOUT_PAGE"; then | ||
| + | echo "CRITICAL: logout не выполнен, ошибка token" | ||
| + | exit 2 | ||
| + | fi | ||
| + | |||
| + | if grep -qiE 'login' "$LOGOUT_PAGE" || grep -qi 'logged out' "$LOGOUT_PAGE" || grep -qi '_task=login' "$LOGOUT_PAGE"; then | ||
| + | echo "OK: logout выполнен" | ||
| + | exit 0 | ||
| + | fi | ||
| + | |||
| + | echo "WARNING: logout отправлен, но результат неоднозначен" | ||
| + | exit 1 | ||
| + | </code> | ||
| + | |||
| ==== Использование диалоговых окон ==== | ==== Использование диалоговых окон ==== | ||
| Line 558: | Line 678: | ||
| === Использование программы dialog (FreeBSD) === | === Использование программы dialog (FreeBSD) === | ||
| - | |||
| <code> | <code> | ||