Перейти к главному содержимому

bash: запуск процессов на фоне

Если надо запустить скрипт на фоне (типовая ситуация - запуск скрипта как CGI из веб-сервера), то перед запуском долгого процесса надо отсоединить stdout и stderr от скрипта. Тогда веб-сервер сможет продолжать работать.

Делается это так (перед запуском фоновой задачи):

exec >&-
exec 2>&-

Источники:

https://stackoverflow.com/questions/6033780/run-a-cgi-shell-script-in-background

https://tldp.org/LDP/abs/html/io-redirection.html

Настройка nginx для вызова скриптов через CGI

nginx будет работать через FastCGI c сервером fcgiwrap, который и будет запускать скрипты через CGI.

Установка и настройка

Дальнейшие действия следует производить от имени root.

Установить серверы:

apt install nginx-full fcgiwrap

Создать файл конфигурации /etc/nginx/fcgiwrap.conf для nginx:

location /cgi-bin/ {
    gzip off;
    root  /var/www;
    fastcgi_pass  unix:/var/run/fcgiwrap.socket;
    include /etc/nginx/fastcgi_params;
    fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;
}

Создать каталог для cgi-скриптов:

mkdir /var/www/cgi-bin
chmod 755 /var/www/cgi-bin

Добавить в файл конфигурации /etc/nginx/sites-available/default строку include fcgiwrap.conf;

server {
        .....
        .....
        include fcgiwrap.conf;
}

Включить fcgiwrap и перезапустить nginx:

systemctl enable fcgiwrap
systemctl restart nginx

Проверка

Создать тестовый файл /var/www/cgi-bin/index.cgi:

#!/usr/bin/env python3

print("Content-type: text/html\n")
print("<html>\n<body>")
print("<div style=\"width: 100%; font-size: 40px; font-weight: bold; text-align: center;\">")
print("CGI Script Test Page")
print("</div>")
print("</body>\n</html>")

Сделать файл исполняемым

chmod 705 /var/www/cgi-bin/index.cgi

Проверить можно по ссылке вида http://servername/cgi-bin/index.cgi.

Скрипт не обязательно должен быть на python, можно использовать bash.

#!/bin/bash

printf "Content-type: text/html\r\n"
printf "\r\n"
printf "<html>\n<body>"
echo "<div style=\"width: 100%; font-size: 40px; font-weight: bold; text-align: center;\">"
printf "CGI Script Test Page"
printf "</div>\n"

echo `whoami`

printf "</body>\n</html>\r\n"

Источник: https://www.server-world.info/en/note?os=Debian_11&p=nginx&f=8

Преобразовать svg в pdf

Преобразовать SVG в PDF

Преобразовать svg файл в pdf можно при помощи программы rsvg-convert.

Для установки её в Debian:

apt install librsvg2-bin

Для Windows всё немного сложнее, понадобится MSYS. В его терминале выполнить:

pacman -S mingw-w64-ucrt-x86_64-librsvg

Обрезать PDF

Вариант 1. pdfcropmargins

Установить можно через pip3:

pip3 install pdfCropMargins --upgrade --only-binary pymupdf

Вариант 2. pdfcrop

Для обрезки pdf-файлов можно использовать pdfcrop из состава TeXLive. Под Windows надо установить TeXLive, для Debian можно только часть (но зависимостей будет много):

apt install texlive-extra-utils

Скрипт для преобразования всех SVG файлов в каталоге

При использовании pdfcropmargins:

#!/bin/sh

rm -f *.pdf
for v in *.svg
do
  if [ -f "$v" ]; then
    FNAME="${v%.*}"
    rsvg-convert -f pdf -o "$FNAME.pdf" "$v"
    pdfcropmargins -p 0 -p4 0 0 0 0 -A "$FNAME.pdf"
  fi
done

При использовании pdfcrop:

#!/bin/sh

rm -f *.pdf
for v in *.svg
do
  if [ -f "$v" ]; then
    FNAME="${v%.*}"
    rsvg-convert -f pdf -o "$FNAME.pdf" "$v"
    pdfcrop "$FNAME.pdf"
  fi
done

Windows

bat-файл для Windows для преобразования одного файла:

@echo off

:: FNAME=имя файла без расширения
set FNAME=%~n1
set RSVG_PATH=C:\msys2\ucrt64\bin

%RSVG_PATH%\rsvg-convert.exe -f pdf -o %FNAME%.pdf %FNAME%.svg

pdfcropmargins -p 0 -p4 0 0 0 0 -A %FNAME%.pdf

Системные сертификаты в python requests

При запросе по https при помощи requests из скрипта на python есть несколько вариантов для проверки сертификата. За это отвечает параметр verify.

Отключение проверки

Если параметр verify равен False, то проверка будет отключена. Это в целом нехорошо, да и будут выводиться всякие предупреждения. Для закрытой локалки как временное решение может и сойдёт...

import requests

r = requests.get(url, verify=False)

Проверка по умолчанию

Если параметр verify равен True (это значение по умолчанию), то проверка будет проводиться на соответствие python-certifi.

import requests

r = requests.get(url, verify=True)

Проверка "вручную"

Можно вручную сохранить сертификаты в текстовый файл (всю цепочку, от корневого центра до сертификата сайта) и путь до этого файла дать в качестве параметра. Тогда сертификаты будут проверяться на соответствие сохраненным в этом файле.

import requests

r = requests.get(url, verify='/path/to/certfile')

Использование системных сертификатов

Обычная включенная проверка (verify=True) проверяет сертификаты "встроенные" в certifi, при этом игнорируя сертификаты установленные в системе. Иногда это неудобно. Решением данной проблемы может служить установка пакета pip-system-certs:

pip3 install pip-system-certs

После этого обычная проверка (verify=True) будет учитывать установленные в системе сертификаты.

Источник: https://stackoverflow.com/questions/50422136/python-requests-with-wincertstore

LaTeX: параметры ключ=значение

Определение команды:

\ExplSyntaxOn

\keys_define:nn { mymodule }
  {
    color .tl_set:N = \l_mymodule_color_tl ,
    color .initial:n = { black } ,
    text .tl_set:N = \l_mymodule_text_tl ,
    text .initial:n = { Default~Text } ,
    size .dim_set:N = \l_mymodule_size_dim ,
    size .initial:n = { 12pt } ,
  }

\NewDocumentCommand { \mycommand } { O{} }
  {
    \keys_set:nn { mymodule } { #1 }
    \group_begin:
      \color{\l_mymodule_color_tl}
      \fontsize{\l_mymodule_size_dim}{\dim_eval:n{\l_mymodule_size_dim * 1.2}}\selectfont
      \l_mymodule_text_tl
    \group_end:
  }

\ExplSyntaxOff

Использование:

\begin{document}

\mycommand % Uses default values
\par
\mycommand[color=blue, text=Hello~World, size=18pt]
\par
\mycommand[size=24pt, color=red]

Свойства ключей в keys_define

Каждый ключ в keys_define может иметь набор свойств:

  • .code:n = code to execute: задает код для выполнения, когда ключ задан, при этом в коде может использоваться #1 и туда будет подставлено значение ключа.
  • .initial:n = initial value: Задает начальное значение. Оно будет использоваться, если ключ вообще не задан.
  • .default:n = default value: Задает значение по умолчанию. Оно будет использоваться если ключ задан без значения (например, key=).
  • .choices:nn = { список выбора }: Задает список допустимых значений для ключа. Для каждого возможного значения задается код, который должен выполниться в соответствующем случае.
  • .bool_set:N, .bool_set_true:N, .bool_set_false:N: Задает что делать для boolean-ключей, установить значение, true или false.
  • .int_set:N, .dim_set:N, .tl_set:N: Задает присвоение переменным для числа, размера или строки.

Пример:

\ExplSyntaxOn
\keys_define:nn { mymodule }
  {
    color .code:n = \tl_set:Nn \l_mymodule_color_tl { #1 },
    color .initial:n = black,
    shape .choices:nn =
      {
        circle .code:n = \tl_set:Nn \l_mymodule_shape_tl { circle },
        square .code:n = \tl_set:Nn \l_mymodule_shape_tl { square }
      },
    shape .initial:n = circle,
    linewidth .int_set:N = \l_mymodule_linewidth_int,
    linewidth .initial:n = 1
  }
\ExplSyntaxOff

В этом примере определены ключи color, shape и linewidth для модуля mymodule.

color принимает значение, shape значение из списка, a linewidth задает числовую переменную.

LaTeX mbox на список

Есть: строка, разделенная запятыми.

Надо: завернуть каждый элемент отдельно в функцию (например, в \mbox) и собрать строку обратно, возможно с другими разделителями.

\ExplSyntaxOn

\NewDocumentCommand{\MBoxingList}{O{,\ }m}
{
  \seq_clear_new:N \l__in_seq
  \seq_set_from_clist:Nn \l__in_seq {#2}
  \seq_set_map:NNn \l__in_seq \l__in_seq {\mbox{##1}}
  \seq_use:Nn \l__in_seq {#1}
%  \quad\seq_count:N \l__in_seq
}

\ExplSyntaxOff

Использовать так: `\expanded{\MBoxingList[, ]{123, 123, 5234, 6543}}

Как вариант определить через \NewExpandableDocumentCommand, но тогда вызывать без \expanded и могут быть сюрпризы если исходная строка передается не явно, а определена командой.

P.S. Вроде и работает, но с этим expansion что-нибудь да не нравится. В общем, глаз да глаз.

P.P.S. Можно попробовать через пакет listofitems.

P.P.P.S Есть какое-то решение на классическом синтаксисе:

\makeatletter

% Functional foreach construct
% #1 - Function to call on each comma-separated item in #3
% #2 - Parameter to pass to function in #1 as first parameter
% #3 - Comma-separated list of items to pass as second parameter to function #1
\def\foreach#1#2#3{%
  \@test@foreach{#1}{#2}#3,\@end@token%
}

% Internal helper function - Eats one input
\def\@swallow#1{}

% Internal helper function - Checks the next character after #1 and #2 and
% continues loop iteration if \@end@token is not found
\def\@test@foreach#1#2{%
  \@ifnextchar\@end@token%
    {\@swallow}%
    {\@foreach{#1}{#2}}%
}

% Internal helper function - Calls #1{#2}{#3} and recurses
% The magic of splitting the third parameter occurs in the pattern matching of the \def
\def\@foreach#1#2#3,#4\@end@token{%
  #1{#2}{#3}%
  \@test@foreach{#1}{#2}#4\@end@token%
}

\makeatother

%% Функция для использования
\def\makembox#1#2{\mbox{#2}, }

HTML redirect

Перенаправить статически страницу можно html-тегом <meta... внутри <head>...</head>, можно при помощи javascript. Лучше использовать и то и другое. И на всякий случай ещё и явную ссылку, вдруг у кого-то браузер сам не перейдёт.

Вот пример:

<!DOCTYPE HTML>
<html lang="en-US">
<head>
  <meta charset="UTF-8">
  <!-- html redirect with timeout=0 -->
  <meta http-equiv="refresh" content="0; url=http://example.com">
  <!-- for search engines -->
  <link rel="canonical" href="http://www.example.com"/>
  <!-- javascript redirect -->
  <script type="text/javascript">
      window.location.href = "http://example.com";
  </script>
  <title>Page Redirection</title>
</head>
<body>
  <!-- Note: don't tell people to `click` the link, 
       just tell them that it is a link. -->
  If you are not redirected automatically, 
  follow this <a href='http://example.com'>link to example</a>.
</body>
</html>

Вызов сторонних скриптов из LaTeX

Latex при сборке документа может вызывать сторонние программы. Иногда это удобно.

По умолчанию такое поведение запрещено, но опцией командной строки --shell-escape это разрешается.

Настройка latexmk

Если сборка производится через latexmk, то в файл конфигурации latexmkrc надо добавить строчки:

push @extra_pdflatex_options, '-shell-escape';
push @extra_xelatex_options, '-shell-escape';
push @extra_lualatex_options, '-shell-escape';

Альтернативный вариант для того же latexmkrc переопределить переменные для запуска, по сути:

$latex = 'latex  %O  --shell-escape %S';
$pdflatex = 'pdflatex  %O  --shell-escape %S';

В документе

В самом документе можно вызывать внешние программы с параметрами и сразу же вставлять на это место документа их выхлоп. Например:

\makeatletter
\@@input|"python3 ff.py"
\makeatother