- PVSM.RU - https://www.pvsm.ru -
В bash частенько можно столкнуться с ситуацией, когда вроде как уже разобрался, и тут внезапно какая-то магия. Ковырнешь ее, а там еще целый пласт вещей, о которых раньше и не подозревал…
Под катом — несколько забавных задачек на bash, которые (надеюсь) могут оказаться интересными даже для середнячков. Удивить гуру я не надеюсь.., но все же перед тем как залезть под кат, сперва пообещайте ответить на задачки хотя бы для себя вслух — без man/info/google.
Какую одну команду нужно выполнить, чтобы следующая команда из примера вывела Hello на ваш терминал?
$ echo "Hello" > 1
$ cd /proc/$$/fd
$ echo "Hello" > 1
Hello
Суперпользователь может писать в чужие дескрипторы (в процессы, которые созданы другими пользователями), выводя текст на их терминалы.
Именно через этот механизм работает популярная утилита write — когда пользователь может написать другому пользователю сообщение без запуска какого-то мессенджера — просто в его терминал. А для того, чтобы write могла писать в дескриптор другого пользователя, на бинарнике write стоит флаг SGID (пользователи должны быть добавлены в группу tty).
Через этот же механизм подключенных к консоли пользователей система оповещает например о ребутах.
Что выведет следующая команда?
$ cat /home/*/.ssh/authorized_keys
Выдаст ошибку? Выведет первый попавшийся файл? Выведет все файлы?
А куда мы зайдем следующей командой:
$ cd /home/*/.ssh
Какой результат последней команды:
$ cp /home/*/.ssh/authorized_keys .
cp /home/*/.ssh/authorized_keys /home/*/ssh/authorized_new
Даже хотел ее кинуть первой, но решил оставить на закуску. Итак ситуация такая:
# Создадим несколько файлов:
$ touch file{1..9}
$ ls -1
file1
file2
file3
file4
file5
file6
file7
file8
file9
Теперь выведем их через "ls -1" и простой регуляркой отфильтруем первые пять:
$ ls -1 | grep file[1-5]
В результате пусто? Что за? где мои файлы?
$ ls -1 | grep "file[1-5]"
file1
file2
file3
file4
file5
$ mkdir test
$ cd test
$ echo file*
file*
$ touch file1
$ echo file*
file1
$ touch file2
$ echo file*
file1 file2
И мы получаем команду, которая то работает, то неработает, то работает непонятно как.
Написанное выше — общеизвестно, но вот не все знают, что *nix также поддерживает в wildcard перечисление символов [abc] — как в регулярных выражениях.
В нашем случае шелл «раскрыл» маску и передал в grep длинную строку, попытавшись выполнить команду «ls -1 | grep file1 file2 file3 file4 file5». Понятно что grep не смог найти строку, в которой есть сразу все значения и вернул пустой результат.
Если выполнить команду, содержащую wildcard в каталоге, где нет подходящих файлов, она не изменится и мы получим как в предыдущем примере с '*':
$ cd ..;echo file[1-5]
file[1-5]
Кстати частенько даже со старыми знакомыми масками многие новички совершают ошибку, например при выполнении команды find, и получают что-то вроде:
$ find . -name file*
find: paths must precede expression: file2
Вывод: Используйте кавычки!
Кстати, перечисление символов работает и с диапазонами и отрицаниями. Примеры:
$ echo file[1-5]
file1 file2 file3 file4 file5
# выведем файлы, у которых после file идет символ не из диапазона 1-5:
$ echo file[^1-5]
file6 file7 file8 file9
$ basename file.txt .txt
file
Но можно не запускать целый отдельный процесс для такого простого действия, и обойтись внутренними преобразованиями в bash:
$ filename=file.txt; echo ${filename%.*}
file
Или наоборот, отрезать имя файла и оставить только расширение:
filename=file.txt; echo ${filename##*.}
txt
Таким образом, "${filename%.*}" означает — начиная справа налево проходим все символы (*) и доходим до первой точки. Отрезаем найденное.
Если бы мы использовали "${filename%%.*)", то в файлах, где точка встречается больше одного раза, у нас бы оно дошло до последней точки, отрезав лишнее.
$ filename="file.hello.txt"; echo "${filename%%.*}"
file
Первое перенаправление "<" из именованного потока или из файла. Давно известное и годами перетёртое мозолями суровых админов. Поэтому сразу перейдем к двум другим, которые встречаются реже.
<<, так называемая конструкция here document. Позволяет разместить многострочный текст прямо в скрипте и перенаправить его, словно из внешнего потока.
$ cat <<EOF
hello,
Habr
EOF
hello,
Habr
Cat читает данные из файла. Мы перенаправляем ему в STDIN файл — конструкция here document генерит его прямо на месте, поэтому не нужно создавать отдельный файл.
Это действительно удобный способ, чтобы вызвать какую-то внешнюю утилиту и скормить ей много данных. Но в последнее время я предпочитаю пользоваться <<<
#!/bin/bash
. load_credentials
sqlplus -s $connstring << EOF
set line 1000
select name, lastlogin from users;
exit;
EOF
#!/bin/bash
. load_credentials
SLQ_REQUEST="
set line 1000
select name, lastlogin from users;
exit;"
sqlplus -s ${connstring} <<<"${SQL_REQUEST}"
На мой взгляд второй вариант выглядит потенциально удобнее. Мы можем задать многострочную переменную в удобном для нас месте, и использовать ее в <<<.
А при коротком запросе все выглядит вообще прекрасно:
#!/bin/bash
. load_credentials
sqlplus -s ${connstring} <<<"select name, lastlogin from users;exit;"
Если оперировать скриптами побольше, и запросами подлиннее, то использование <<< с перенаправлениеим из переменных, а сами переменные мы можем объявить заранее, в специально отведенном и оборудованом комментариями месте, то код получается гораздо читабельнее.
Только представьте себе, что вам нужно вызвать несколько внешних команд с перенаправлением им кучи многострочных данных, и расположить эти команды например внутри нескольких if/loop конструкций разной вложенности.
here document сильно портит форматирование и читабельность подобного кода будет ужасной.
# создаем директорию test
$ mkdir test
# выводим информацию о количестве ссылок и номер iNode для test
$ stat -c "LinkCount:%h iNode:%i" test
LinkCount:2 iNode:522366
Как? Только создали и уже два линка?
# заходим в созданную директорию test
$ cd test
# внутри выводим статистику для текущей директории "."
$ stat -c "LinkCount:%h iNode:%i" .
LinkCount:2 iNode:522366
В обоих случаях мы видим тот же номер iNode. То есть test и "." внутри него — это та же самая директория. И "." это не какой-то специальный алиас баша, и даже не операционной системы. Это просто жесткая ссылка на уровне файловой системы. Проверим еще один момент:
# создаем поддиректорию test2 внутри нашего test
$ mkdir test2
# заходим в поддиректорию test2
$ cd test2
# смотрим статистику о родительской директории ".."
$ stat -c "LinkCount:%h iNode:%i" ..
LinkCount:3 iNode:522366
".." имеет тот же же iNode, что и предыдущие. И счетчик ссылок увеличился.
Итог: жесткие ссылки на папки — обязательная часть файловой системы, которая используется для построения дерева директорий. Однако, если дать возможность пользователю создавать произвольные хардлинки на директории, он может ошибиться и создать зацикленную ссылку.
При этом все команды, пробегающие по дереву каталогов (find, du, ls) уйдут в бесконечный цикл, завершаемый только прерыванием или stack overflow, поэтому пользовательской команды нет.
На этом у меня все. Пользуясь случаем, заранее передаю спасибо тем, кто отметится в опросе!
!function(e){function t(t,n){if(!(n in e)){for(var r,a=e.document,i=a.scripts,o=i.length;o--;)if(-1!==i[o].src.indexOf(t)){r=i[o];break}if(!r){r=a.createElement("script"),r.type="text/javascript",r.async=!0,r.defer=!0,r.src=t,r.charset="UTF-8";;var d=function(){var e=a.getElementsByTagName("script")[0];e.parentNode.insertBefore(r,e)};"[object Opera]"==e.opera?a.addEventListener?a.addEventListener("DOMContentLoaded",d,!1):e.attachEvent("onload",d):d()} } }t("//top-fwz1.mail.ru/js/code.js","_tmr"),t("//mediator.imgsmail.ru/2/mpf-mediator.min.js","_mediator")}(window);
Только зарегистрированные пользователи могут участвовать в опросе. Войдите [1], пожалуйста.
+3
window._yaparams = {'hubs':[], 'flow':'admin (Администрирование)'};
// hubs to GA
_yaparams['hubs'].push('sys_admin (Системное администрирование)');
_yaparams['hubs'].push('shells (Оболочки)');
_yaparams['hubs'].push('nix (*nix)');
Автор: Сергей Кулик
Источник [30]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/bash/264985
Ссылки в тексте:
[1] Войдите: https://habrahabr.ru/auth/login/
[2] bash: https://habrahabr.ru/search/?q=%5Bbash%5D&target_type=posts
[3] Подробнее: https://www.pvsm.ru/adblock/
[4] Реклама: https://tmtm.ru/services/advertising/
[5] Управление задачами в Jenkins: https://habrahabr.ru/company/selectel/blog/339390/
[6] Мониторинг головного мозга: https://habrahabr.ru/post/339330/
[7] Управляем Windows Server (Core) с помощью веб-интерфейса Project Honolulu от Microsoft: https://habrahabr.ru/post/339372/
[8] Практика настройки Mikrotik для чайников: https://habrahabr.ru/post/265387/
[9] [Видео] Орки тут: парадигмы систем оркестрации, Docker, Mesos: https://habrahabr.ru/company/yamoney/blog/339350/
[10] APDEX и замеры производительности 1С: https://habrahabr.ru/company/knopka/blog/339394/
[11] Сергей Кулик: https://www.pvsm.ru/users/saboteur_kiev/
[12] Bash Booster — SCM инструмент на чистом баше: https://www.pvsm.ru/post/253209/
[13] Учим bash-скрипты, пишем Sokoban: https://www.pvsm.ru/post/120198/
[14] Использование bash completion в командной строке, собственных скриптах и приложениях. Часть 1: https://www.pvsm.ru/post/71525/
[15] полноправные пользователи: https://www.pvsm.ru/info/help/registration/
[16] Сейчас: #broadcast_comments_now
[17] Вчера: #broadcast_comments_yesterday
[18] Неделя: #broadcast_comments_week
[19] Какие налоги нужно платить при выводе доходов от приложений в Apple iTunes: https://habrahabr.ru/company/it-lex/blog/339412/
[20] Необразованная молодёжь. Ответ бизнеса: https://habrahabr.ru/company/regionsoft/blog/339284/
[21] Так ли легко переехать в Германию? Моя личная статистика поиска работы: https://habrahabr.ru/post/339300/
[22] Фетиш LaTeX (или Не пишите в LaTeX! Он только для вёрстки): https://habrahabr.ru/post/339340/
[23] Онлайн-квест от MBLTdev. Призы от JetBrains: https://habrahabr.ru/company/e-Legion/blog/339334/
[24] Как мы торговали играми из киосков с газетами: https://habrahabr.ru/company/mosigra/blog/339302/
[25] Самое сложное в программировании это…: https://habrahabr.ru/post/339356/
[26] Необразованная молодёжь: https://habrahabr.ru/post/339022/
[27] Необразованная молодёжь. Ответ преподавателя-совместителя: https://habrahabr.ru/post/339208/
[28] Пора убить веб: https://habrahabr.ru/post/338880/
[29] На шаг ближе к С++20. Итоги встречи в Торонто: https://habrahabr.ru/company/yandex/blog/336264/
[30] Источник: https://habrahabr.ru/post/339246/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.
Только полноправные пользователи [15] могут оставлять комментарии. Войдите [1], пожалуйста.