Tags: shell

nyaload

Всё есть строка

Я просто хотел узнать, как передать bash-функцию как параметр в подпроцесс ( export -f function_name ) .

my_func() { echo hello; }
export -f my_func
python -c 'import os; os.system("my_func")' #печатает "hello"
echo 1 2 | xargs -n 1 bash -c my_func #печатает "hello" 2 раза

А оказалось, что ещё можно bash-функции сериализовать и выполнить через ssh на другом хосте.


foo() { echo "hello from $(hostname)"; }
ssh host "$(declare -f foo) ; foo"


( отсюда: http://unix.stackexchange.com/questions/22796/can-i-export-functions-in-bash )
nyaload

logical A ? B : C

Насколько я понимаю, в shell нельзя выразить if A ; then B ; else C ; fi через операции &&, ||, ! так, чтобы сохранить побочные эффекты. Простое доказательство не вижу, но если перебирать разные варианты "что слева и справа от корневой операции", то видно что какую-то команду придётся выполнить дважды.
Пара неработающих примеров:
(A && B) || C — когда A=true B=false C=true то return code выражения целиком это true, хотя хочется false.
(A && B) || (! A && C) — A может вызываться дважды

update: если добавить команду exit, то возможно:
( A && { B || exit 1 ; } || C )
Круглые скобки порождают подпроцесс, exit выходит из него. Фигурные скобки - только для для группировки выражения, как обычные скобки в математике. && приоритетней ||, так же как умножение приоритетней сложения. Ну и стандартная unix-путаница "1 это false, 0 это true".
nyaload

a2p bug

"a2p" program translates awk programs to perl programs. Tried it, immediately bumped into a different interpretation of "$0":

echo A B C D E | awk '{ $3="x"; print $0; }'
A B x D E

echo A B C D E | perl -e "$(echo '{ $3="x"; print $0; }' | a2p)"
A B C D E

upd: patches and more bugs
nyaload

Внезапно сетевая утилита

Команда ls, чтобы напечатать имена пользователей и групп - ходит на RADIUS-сервер аутентификации (изредка, если не закешировано).

Не знаю как админы так настроили, это почти не мешает, просто удивляет что тулза которой вроде бы сеть не нужна - внезапно ходит в сеть, совершенно неожиданно.

Это касается не только ls, а любых инструментов которые печатают имя пользователя (через сишный getpwuid_r например). Имейте ввиду, что вполне реально подвиснуть на несколько секунд при определении имени пользователя.
nyaload

tar --to-command

streaming-обработка файлов упакованых в tar.gz, который лежит в интернете:
curl example.net/some.tar.gz | tar -xzf - '--to-command=my_script $TAR_FILENAME $TAR_SIZE'

tar.gz - ужасный формат. Оптимизирован под бэкапы на магнитную ленту, в остальном всё плохо.
Чтобы прочитать файл с нужным именем из архива - надо скачать из интернета и распаковать всё, что лежит до него. Заголовки с именами и размерами запакованых файлов - тоже сжаты в gz и рассеяны по разным местам файла!
nyaload

bash command prompt

Мой command prompt в linux - на трех строках.
Первая - status line. в теории лишняя, на практике - всякие мелочи мешают взять и оторвать. В неё можно напихать много всего (svn/git/hg status например) у меня простенькая tty:user@host $pwd
Вторая, в которой ввод команды - начинается сразу от края экрана без этих $ и #.
Третья - просто пустая.

Плюсы:
1) Легче в терминале скопировать мышкой команду, не нужно тщательно целиться чтобы не зацепить $ в начале команды. Даблклик по строчке, и всё.
2) если вывод команды без EOL - нет противного приклеивания PROMPT к выводу. Так же пустая строка отделяющая команды - позволяет легче читать сессию команд в консоли.
3) набираемая команда - всегда в одной точке, упрощение моторики глаз.
4) Во второй строке умещается больше информации (длинные пути). Вообще эту информацию надо пихать в какой-нибудь status-бар, а не строку тратить, но я не знаю безглючного способа это сделать, заголовок окна по многим причинам не удобен (я всё ещё не освоил tmux, давно пора).

Если вас раздражала какая-то из этих проблем в bash - то теперь не будет. Возможно, для пользователей tmux или zsh они и так не существуют.

Скриншот: Collapse )

Настройка: export PS1="\[\e]0;\w\a\]\n\[\e[32m\]\l:\u@\h \[\e[33m\]\w\[\e[0m\]\n"
Информацию о цветах и всех этих \u@\h ( user@host ) легко найти в интернете, например http://www.kirsle.net/wizards/ps1.html
nyaload

poor man's profiler

Почему-то для меня каждый раз оказывается, что вспомнить как инсталлировать, запустить настоящий профайлер и его вьювер (без детализации по каждому кеш-промаху) - сложнее, чем позвать в цикле gdb.

while true; do gdb -p 19974 -ex "bt" --batch >> gdb.prof.txt ; sleep 0.1 ; done

valgrind --tool=callgrind подавал некоторые надежды в плане запоминаемости, но тормозит до неюзабельности. google profiler я забыл как запускать и инсталлировать. gprof - нужно пересобрать код и вспомнить как в билд-систему подсунуть -gp. Установка perf - у меня где-то косяк с репозиториями убунты, и тоже не помню как его запускать.

Вообщем, если можете - делайте тулзы удобными для тех, кто запускает их раз в год.
gdb я запускаю чаще, где-то раз в месяц, поэтому у меня с ним лучше, а вот вспомнить с каким ключами я инсталлировал/компилировал, запускал, и annotatировал - плохо.
nyaload

Слепая консоль.

Когда сидишь через длинную цепочку SSH-соединений, самый простой способ скопировать небольшой текстовый файл - это скопировать его мышкой с экрана.

В эти моменты начинаешь понимать, что командная строка иногда сосет, так как требует слишком детального инструктирования слепого компьютера.
Консоль - СЛЕПАЯ, не видит куда я пальцем тычу, требует описать всё в терминах "3 шага на юг, 12 на восток, залезть в люк, в люке скажи следующему исполнителю, сделать 3 шага на юг, 12 на восток, залезть в люк, передать следующему исполнителю, что первые две буквы на бирке - жо" .
И шизофреничная, на каждом хосте - свой мозг, и каждому - поди объясни как общаться с соседним мозгом. И сидишь ты с ними, видишь эту компанию-матрёшку насквозь, а она сама себя не видит.
nyaload

bash linux repeat: printf

Команда printf довольно мощная, часто позволяет обойтись без циклов:

function f { printf "%.0s$1$2" $(seq 10); printf "%.0s$1" ; }
printf "$(f "$(f + ----)\n" "$(f '|' " %%%%2s ")\n")" $(seq 0 99)

Вывод:Collapse )

Пояснение: "%.0s" печатает аргумент как пустую строку.
printf "%.0sXYZ" $(seq 1 20) - повторяет строку "XYZ" 20 раз.
Как обычно, заботливо подложены грабли: printf воспринимает 0 аргументов как один пустой аргумент. А не как 0 аргументов.

upd: Кто-то интересовался однострочниками на питоне:
python -c "print (lambda f:f(f('+', '----') + '\n', f('|', ' %2s ') + '\n') % tuple(range(0, 100)))(lambda a, b: a + 10*(b+a))"
nyaload

Языки для тренировки темной стороны Силы

python научил меня программировать, не теряя время на ненужную оптимизацию кода.

bash/shell учит меня программировать без траты мозга на чтение документации, копипастом готовых решений со stack overflow

Я даже не пытаюсь почитать документацию или мега-книжки типа ABSG, имеющегося уже достаточно для понимания, что уложить знания по shell в систему небольшого числа независимых кубиков невозможно. Это не кубики, а набор гёмбёцов.
фичи bash и утилит -

  • не ортогональны
    START=1 ; END=5 ; echo {1..5} {$START..$END}
    VAR={1..5}; echo $VAR
    обработка ошибок из prog в VAR=$(prog)
    строковые функции, работающие только с переменными

  • не мнемоничны. bash-redirections-cheat-sheet.pdf, или строковые функции, работающие только с переменными
  • глючат с UTF-8 ( echo {p..z} {п..ц} ),

  • выносящие мозг неожиданные ограничения в синтаксисе без понятной диагностики ( если забыть пробел после '[','{' или ';' перед '}', то получаем невнятную ошибку )

  • содержат рандомные грабли в виде внезапных исключений в обработке входа, типа \r для read без -r, или пробелов для read -r, или многострочный текст при присваивании в переменную

  • автор честно пишет, что синтаксиса bash не существует, документация синтаксиса - это код интерпретатора,

  • при попытке использовать неканоничные редкие фичи - коллеги перестают понимать твой код,

  • самостоятельно написаный код - наверняка содержит неизвестные баги (можно сделать одно и тоже 10-ю способами, все работают, но надёжен только один каноничный способ, а иначе параметр с минусами, пробелами и EOL сделает что-то случайное ).

  • Нет структур данных. Нельзя сделать массив структур (может и можно, но это advanced-хакерство вне туториалов)

  • Почти всегда 0 объектов воспринимается как особый случай, требующий отдельной обработки. cp *.txt dir не сработает из-за особой обработки 0 объектов сразу в двух местах. И так везде.



Тем не менее, в задачах "запустить 5 программ и прописать им параметры ввода-вывода, склеить пути и скопировать файлы" он лаконичней и проще чем python. ( например,
set -euo pipefail
IN=$1
OUT=$2
test -d $OUT/output && mkdir -p $OUT/output;
prog1 $IN/in.txt $( printf " --rule %s\n " $IN/rules/*.rule ) | prog2 $(date --date='week ago' +%s) > $OUT/output/out.txt
).