bash
Bolt — автоматическое обновление конфигурации «Апача» на «Маке»
Добавил новую программу в свои «Игры с шелом», назвал «Болт», она следит за изменением папки, куда у вас на «Маке»
Запускать нужно так (из командной строки):
sudo тутполныйпуть/bolt.sh &Потом ввести пароль администратора. Если затем в папке с сайтами создать, например «site1», то в браузере сразу можно набирать «http://site1», он уже будет открываться. Программа умеет убирать за собой (после перезагрузки компьютера, например).
Скачать можно с «Гитхаба».
Как заменить табы, используя sed
Утилита командной строки sed (это потоковый редактор),
Я немного поэксперементировал, оказалось, что sed вполне воспринимает этот символ как таковой, а все «магические выражения» не работают. Поскольку «таб» имеет специальное значение в командной строке, ввести его можно либо через комбинацию Ctrl+V, tab, либо Ctrl+V, Ctrl+I. Во многих шеллах (например, в bash, ksh, sh) сработает специальный синтаксис с долларом, как в примере ниже.
Например, если вам надо заменить последовательные «табы» на один, то это может выглядеть вот так:
sed $'s/\t\t*/\t/g' sample.txt # именно \t\t*, а не \t+
# или
sed -E $'s/\t+/\t/g' sample.txt # в Линуксе ключ „-r“Если вы знаете как в sed можно работать с tab проще, расскажите, пожалуйста, в комментариях.
Интерактивная игра на bash: «Арканоид» ★
После шахмат, где я решал проблему опроса клавиатуры, мне захотелось попробовать сделать
Забегая вперёд, скажу, что проблему решить вполне удалось. Я разделил игру на два процесса, один из которых опрашивает клавиатуру и сообщает о нажатии второму при помощи сигналов — USR1, USR2 и HUP, как раз три сигнала по трём управляющим клавишам — „←“, „→“ и «пробел». Последняя нужна, чтобы пускать шарик.
Решил сделать «Арканоид», не совсем классическую версию (на неё мне ещё бы пара вечеров потребовалась), но близкую. В игре есть три типа блоков разных цветов — вишнёвый разбивается сразу, синий при первом ударе превращается в вишнёвый, а от зелёного (самое интересное!) при ударе иногда отваливается часть, поймав которую, можно получить приятный бонус — более широкую ракетку, дополнительную жизнь или липкость. Последнее означает, что шарик в этом режиме не отскакивает от ракетки, а прилипает.

Ещё одна фишка игры — звуковое оформление, которое нечасто услышишь в консоли, я думаю. Правда, только для «Мака» (сделано командой «say», я заставляю её проговаривать буквы с большой скоростью), знаю, что для Линукса тоже есть команды для синтезатора речи («espeak», например), но мне негде их попробовать.
В игре пять жизней и пять уровней, кстати второй посвящён моей любимой жене, большой любительнице кошек (этот уровень как раз на скриншоте). Я сделал щадящую скорость полёта шарика, так что игру можно пройти даже без потерь, если хорошо потренироваться. Код, как водится, выложен на «Гитхаб».
От терминала, как и в шахматах, требуется уметь отображать 256 цветов и хорошая поддержка «Юникода». Нигде, кроме как под «Мак» игру я не тестировал,
Я записал небольшое видео игрового процесса. Я попробовал две программы для записи видео с экрана — «Скрини» и «КвикТайм», к сожалению обе нагружают процессор так, что игра начинает тормозить.
Видео выложил на «Яндекс.Видео». Добавлено позднее: сервис «Яндекс.Видео» прекратил своё существование.
Сетевая игра на bash: шахматы ★
Я давно хотел написать
Поскольку тонкости управления с клавиатурой съели очень много моего времени, я не стал заморачиваться с тонкостями совместимости, поэтому игра тестировалась только под Mac OS X, есть ненулевая вероятность, что она заработает и под Linux и уж точно её можно допилить там до рабочего состояния.
Для работы игра требует наличия nc (aka Netcat) и терминала с поддержкой 256 цветов (под Mac OS рекомендую iTerm2). При наличие интереса к игре, допилю до терминала на 16 цветов и /dev/tcp. Кстати начал выкладывать все свои
Эта игра запускается посложнее, так как сетевая, у неё два параметра, о которых она расскажет, если её запустить без них. Первый — адрес машины противника, второй — порт. Порт выбирается одинаковым на обеих машинах. Игру можно запустить и на одной машине, в двух консолях (на скриншоте как раз такой случай).
Играть просто — в каждый момент времени активна только одна доска (на скриншоте — правая, у неё буквы и цифры вокруг доски ярче), на активной доске курсор двигается курсорными клавишами — ←, →, ↑ и ↓, взять фигуру и поставить её на доску — по клавише пробела или Enter. Как только вы поставили фигуру на доску, ход переходит к сопернику. «Съесть» фигуру соперника проще простого — достаточно поставить свою фигуру на чужую. В игре есть защита — нельзя «съесть» свою фигуру.
Ничего помимо этого в игре нет — не производится правильность контроля ходов, нет проверки на завершение игры, можно даже ходить фигурами соперника. Было очень сложно придумать как обрабатывать нажатия в shell, так что остальное сделать я просто не успел, не поместилось в формат «игрушка за вечер».
#!/bin/bash
# Network chess by Evgeny Stepanischev //bolknote.ru 2011
if [ $# -ne 2 ]; then
echo Usage: $0 host-of-opponent port
exit
fi
# Хост оппонента
HOST="$1"
# Общий порт
PORT="$2"
# Клавиатурные комбинации извстной длины
SEQLEN=(1b5b4. [2-7]. [cd]... [89ab].{5} f.{7})
# Фигуры
WHITE=(♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙ ♖ ♘ ♗ ♕ ♔ ♗ ♘ ♖)
BLACK=(♜ ♞ ♝ ♛ ♚ ♝ ♞ ♜ ♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟)
# Наш ход?
OURMOVE=
# Я чёрный или белый?
MYCOLOR=
# Доска
declare -a XY
# Курсор
CX=1 CY=7
TAKEN=
# Необходимые нам клавиатурные коды
KUP=1b5b41
KDOWN=1b5b42
KLEFT=1b5b44
KRIGHT=1b5b43
KSPACE=20
# Восстановление экрана
function Restore {
echo -ne "\033[5B\033[5B\033[?25h\033[m"
stty "$ORIG" 2>/dev/null
(bind '"\r":accept-line' 2>/dev/null)
}
trap Restore EXIT
# Выключаем Enter
(bind -r '\r' 2>/dev/null)
# Выключаем остальную клавиатуру
ORIG=`stty -g`
stty -echo
# Убирам курсор
echo -e "\033[?25l"
# Отдаём события клавиатуры в сеть
function ToNet {
echo $1 | nc "$HOST" "$PORT"
}
# Реакция на клавиши курсора
function React {
case $1 in
$KLEFT)
if [ $CX -gt 1 ]; then
CX=$(($CX-1))
PrintBoard
fi
;;
$KRIGHT)
if [ $CX -lt 8 ]; then
CX=$(($CX+1))
PrintBoard
fi
;;
$KUP)
if [ $CY -gt 1 ]; then
CY=$(($CY-1))
PrintBoard
fi
;;
$KDOWN)
if [ $CY -lt 8 ]; then
CY=$(($CY+1))
PrintBoard
fi
esac
# Отдаём события клавиатуры в сеть
[ "$OURMOVE" ] && ToNet $1
}
# Проверка совпадения с известной клавиатурной комбинацией
function CheckCons {
local i
for i in ${SEQLEN[@]}; do
if [[ $1 =~ ^$i ]]; then
return 0
fi
done
return 1
}
# Функция реакции на клавиатуру, вызывает React на каждую нажатую клавишу,
# кроме KSPACE — на неё возвращается управление
function PressEvents {
local real code action
# Цикл обработки клавиш, здесь считываются коды клавиш,
# по паузам между нажатиями собираются комбинации и известные
# обрабатываются сразу
while true; do
# измеряем время выполнения команды read и смотрим код нажатой клавиши
# akw NR==1||NR==4 забирает только строку №1 (там время real) и №4 (код клавиши)
eval $( (time -p read -r -s -n1 ch; printf 'code %d\n' "'$ch") 2>&1 |
awk 'NR==1||NR==4 {print $1 "=" $2}' | tr '\r\n' ' ')
# read возвращает пусто для Enter и пробела, присваиваем им код 20,
# а так же возвращаются отрицательные коды для UTF8
if [ "$code" = 0 ]; then
code=20
else
[ $code -lt 0 ] && code=$((256+$code))
code=$(printf '%02x' $code)
fi
if [ $code = $KSPACE ]; then
[ "$OURMOVE" ] && ToNet $KSPACE
SpaceEvent && return
continue
fi
# Если клавиши идут подряд (задержки по времени нет)
if [ $real = 0.00 ]; then
seq="$seq$code"
if CheckCons $seq; then
React $seq
seq=
fi
# Клавиши идут с задержкой (пользователь не может печатать с нулевой задержкой),
# значит последовательность собрана, надо начинать новую
else
[ "$seq" ] && React $seq
seq=$code
# возможно последовательность состоит из одного символа
if CheckCons $seq; then
React $seq
seq=
fi
fi
done
}
# Проверяем чёрная или белая фигура
function CheckColor {
echo -n ${1:0:1}
}
# Первичное заполнение доски
function FillBoard {
local x y ch
for y in {1..8}; do
for x in {1..8}; do
ch='S '
if [ $y -le 2 ]; then
ch=B${BLACK[$x+8*$y-9]}
else
if [ $y -ge 7 ]; then
ch=W${WHITE[$x+8*$y-57]}
fi
fi
XY[$x+100*$y]=$ch
done
done
}
# Вывод букв по краю доски
function PrintBoardLetters {
local letters=abcdefgh
[ -z "$OURMOVE" ] && echo -ne "\033[30m" || echo -ne "\033[0m"
echo -n ' '
for x in {0..7}; do
echo -n "${letters:$x:1} "
done
echo
}
# Вывод цифры по краю доски
function PrintBoardDigit {
[ -z "$OURMOVE" ] && echo -ne "\033[30m"
echo -en " $((9-$1))\033[0m "
}
# Вывод доски
function PrintBoard {
local x y c ch
local colors=('48;5;209;37;1' '48;5;94;37;1')
PrintBoardLetters
for y in {1..8}; do
PrintBoardDigit $y
for x in {1..8}; do
c=${colors[($x+$y) & 1]}
ch=${XY[$x+100*$y]}
if [[ $CX == $x && $CY == $y ]]; then
c="$c;7"
[ "$TAKEN" ] && ch=$TAKEN
[ $MYCOLOR == B ] && c="$c;38;5;16"
fi
[[ $(CheckColor "$ch") == "B" ]] && c="$c;38;5;16"
echo -en "\033[${c}m${ch:1:1} \033[m"
done
PrintBoardDigit $y
echo
done
PrintBoardLetters
echo -e "\033[11A"
}
# Приём событий
function NetListen {
nc -l $PORT
}
# Готовы слушать события сети
function NetEvents {
local code
while true; do
code=$(NetListen)
[[ "$code" == "$KSPACE" ]] && SpaceEvent && return
React $code
done
}
# Реакция на нажатие Space и Enter — взять или положить фигуру
function SpaceEvent {
local xy
# Проверяем, есть ли фигура под курсором
let xy="$CX+$CY*100"
# Фигуры нет
if [ "${XY[$xy]:-S }" = "S " ]; then
if [ -z "$TAKEN" ]; then
echo -en "\007"
else
# Положили фигуру
XY[$xy]=$TAKEN
TAKEN=
return 0
fi
# Фигура есть
else
# Мы не должны позволять «съесть» свою фигуру
if [[ $(CheckColor "$TAKEN") == $(CheckColor "${XY[$xy]}") ]]; then
echo -en "\007"
else
# Фигура есть «в руке», мы «съедаем» противника
if [ "$TAKEN" ]; then
XY[$xy]=$TAKEN
TAKEN=
return 0
else
# «В руке» ничего не было, мы взяли фигуру
TAKEN=${XY[$xy]}
XY[$xy]="S "
fi
fi
fi
return 1
}
# Очистка клавиатурного буфера
function ClearKeyboardBuffer {
# Быстро — через zsh
which zsh &>/dev/null && zsh -c 'while {} {read -rstk1 || break}' && return
# Медленно — через bash
local delta
while true; do
delta=`(time -p read -rs -n1 -t1) 2>&1 | awk 'NR==1{print $2}'`
[[ "$delta" == "0.00" ]] || break
done
}
FillBoard
# Кто будет ходить первым
ToNet HI
[[ "$(NetListen)" == "HI" ]] && OURMOVE=1
sleep 0.2
ToNet ULOOSE
[ "$OURMOVE" ] && MYCOLOR=W || MYCOLOR=B
PrintBoard
# Основной цикл — обрабатываем события из сети или с клавиатуры
while true; do
if [ -n "$OURMOVE" ]; then
ClearKeyboardBuffer
PressEvents
OURMOVE=
else
NetEvents
OURMOVE=1
fi
PrintBoard
done
Bashnut Battery
Есть такая программа — coconutBattery, красиво показывает под MacOS X состояние батареи и некоторые другие характеристики. Поскольку я тут тренируюсь писать под Bash, решил сегодня повторить её функционал. Полностью не получилось, так как новая версия MacOS X выдаёт

В этом скрипте я разучил несколько новых фокусов, рад что сел за эту задачу. И ещё новинка — я теперь проверяю тип терминала, если он содержит «256» (поддерживаются 256 цветов), то цвета берутся из расширенной палитры. Сам код — далее.
#!/bin/bash
# Хост для информации о серийнике
HOST='www.chipmunk.nl'
# Выбираем информацию о батарее, получится что-то вроде
# Amperage 18446744073709550574 Flags 4 Capacity 6632 Current 6338 Voltage 8192 CycleCount 14 и тд
BATTERY=( $(\
ioreg -w0 -l |
egrep '(Max|Design)Capacity|(Legacy|IO)BatteryInfo|product-name|Temperature|PlatformSerialNumber' |
tee >(awk -F{ '/(Legacy|IO)BatteryInfo/ { gsub(/ |\}|"/, ""); gsub(/,|=/, " "); print $2 }') |
tee >(awk -F'"' '/(Max|Design)Capacity|product-name|Temperature|PlatformSerialNumber/ { gsub(/[=<>-]/, ""); print $2 $3 $4}') |
grep -vF '"' |
tr '\n' ' '
))
# Достаём значение по ключу из BATTERY
function GetBatVal {
local i
for ((i=0; i<${#BATTERY[@]}; i+=2)); do
if [ $1 = ${BATTERY[$i]} ]; then
echo ${BATTERY[$i+1]}
break
fi
done
}
# Получаем информацию о неделе выпуска
function GetPlatform {
local tmpfile="$TMPDIR/battery-age-mac"
# Файл с кешем, чтобы не дёргать сервис каждый раз
if [ -e $tmpfile ]; then
# проверим время создания файла
eval $(stat -s $tmpfile)
# Если кеш устарел, то удаляем его
if [ $((`date +%s` - $st_mtime)) -gt 86400 ]; then
rm -f $tmpfile
else
cat $tmpfile
return
fi
fi
local date=($(\
curl --connect-timeout 3 "http://$HOST/cgi-fast/applemodel.cgi?serienummer=$1" 2>/dev/null |
sed 's/<BR>/`/g' | awk 'BEGIN {RS="`"} /Production (year|week)/{gsub("<[^>]+>", ""); print $2 $3}' |
sort | cut -d: -f2 | tr "\r\n" ' '
))
if [ ${#date[@]} -le 1 ]; then
echo NA
return
fi
local scale
local diff
# Считаем количество недель
let diff="($(date +%Y)-${date[1]})*52177 + ( $(date +%V) - ${date[0]}) * 1000"
# Выбираем что будем отображать — недели, месяцы, годы
if [ $diff -gt 5 ]; then
diff=$(( $diff / 4340 ))
scale=Month
if [ $diff -gt 12 ]; then
diff=$(( $diff / 12 ))
scale=Year
fi
else
diff=$(( $diff / 1000 ))
scale=Week
fi
[ $diff -gt 1 ] && scale=${scale}s
echo $diff $scale | tee $tmpfile
}
# Рисуем прогрессбар
function PrintBat {
# Если терминал поддерживает 256 цветов, покажем красиво
if [[ $TERM =~ 256 ]]; then
local colors=("38;5;160" "38;5;220" "38;5;34")
else
# Иначе, увы, цвета попроще
local colors=(31 33 32)
fi
local c=${colors[0]}
[ $1 -ge 13 ] && c=${colors[1]}
[ $1 -ge 20 ] && c=${colors[2]}
local bar=$(cat)
local prg=$(printf "%0$1s" | tr 0 ${bar:2:1})
local rep="\033[${c}m$prg\033[30m"
echo -e ${bar/$prg/$rep}
}
# Возраст Мака
age=$(GetPlatform `GetBatVal IOPlatformSerialNumber`)
# Всё достаточно очевидно: боксы с информацией
cur=$(GetBatVal Current)
max=$(GetBatVal Capacity)
let percent="($cur*40/$max)"
echo -e '\033[1m\n Bashnut Battery by Evgeny Stepanischev\033[0m'
echo
echo ' Battery charge'
echo ┌──────────────────────────────────────────┐
printf '│ Current charge: % 5d mAh │\n' $cur
printf '│ Maximum charge: % 5d mAh │\n' $max
echo '│ │'
echo -e '│ ████████████████████████████████████████ \033[0m│' | PrintBat $percent
echo └──────────────────────────────────────────┘
des=$(GetBatVal DesignCapacity)
max=$(GetBatVal MaxCapacity)
let percent="($max*40/$des)"
echo ' Battery capacity'
echo ┌──────────────────────────────────────────┐
printf '│ Current capacity: % 5d mAh │\n' $max
printf '│ Design capacity: % 5d mAh │\n' $des
echo '│ │'
echo -e '│ ████████████████████████████████████████ \033[0m│' | PrintBat $percent
echo └──────────────────────────────────────────┘
echo ' Details'
echo ┌──────────────────────────────────────────┐
printf '│ Mac model: % 17s │\n' $(GetBatVal productname)
printf '│ Age of your Mac: % 17s |\n' "$age"
printf '│ Battery loadcycles: % 5d │\n' $(GetBatVal CycleCount)
printf '│ Battery temperature: % 5s˚С |\n' `echo "scale=1;($(GetBatVal Temperature)+5)/100" | bc`
echo └──────────────────────────────────────────┘
echo -e "\033[0m"
Бинарные часы на bash
Раз пошла такая пьянка (в смысле, раз уж день программиста), я на радостях решил не останавливаться на достигнутом и написать

Бинарные часы — популярное сейчас развлечение программистов, вроде написания игры «Жизнь». Как можно догадаться из названия, они показывают время в двоичной системе исчисления. Самое интересное в моей реализации — как подавляется ввод клавиатуры, это неочевидно. Всё дело в следующих строчках:
# Нажатие «Enter» нужно отключать отдельно
bind -r '\r'
# Сохраняем предыдущее состояние
ORIG=`stty -g`
# Отключаем остальную клавиатуру
stty -echo
# На выходе всё нужно восстановить как было
function Restore {
stty "$ORIG"
bind '"\r":accept-line'
}
trap 'Restore' EXITНаверняка не раз ещё пригодится. Сама программа бинарных часов дальше, там у меня несколько сложнее, так как я ещё убираю с экрана курсор, чтобы не мешался. Выйти из программы просто — надо нажать Я писал под «Мак», так что на других системах может и не завестись.Текст программы внутри.
#!/bin/bash
declare -a xy
# Выключаем Enter
bind -r '\r'
# Выключаем остальную клавиатуру
ORIG=`stty -g`
stty -echo
function Restore {
stty "$ORIG"
bind '"\r":accept-line'
echo -ne "\033[5B\033[?25h\033[m"
}
trap 'Restore' EXIT
# Цвета наших «стрелок»
colors=(30 34)
# Очистка графического массива
function Clear {
xy=
}
# Подготовка маски одного разряда
function Print {
mask=$(printf '%08d' `echo "obase=2; $1" | bc`)
let pos="$2*4"
for x in {0..1}; do
for y in {0..3}; do
xy[$pos+$x+$y*100]=${mask:$x*4+$y:1}
done
done
}
# Печать часов на экран
function PrintClock {
echo -e "\033[?25l\033[1mBash Binary Clock by Evgeny Stepanischev\033[0m\n"
for y in {0..3}; do
for x in {0..9}; do
c=${colors[${xy[$x+$y*100]:-0}]}
echo -ne "\033[${c}m▣"
done
echo -e "\033[0m"
done
# после печати часов передвигаем курсов так,
# чтобы следующий кадр выводился поверх предыдущего
echo -en "\033[8A"
}
# Вывод часов
function Clock {
Clear
for i in {0..2}; do
Print $1 $i
shift
done
PrintClock
echo -e "\n"
}
while true; do
Clock `date "+%H %M %S"`
sleep 1
done
Занятость каналов WiFi

Что делать перед днём программиста как не программировать? Я настраивал точку доступа дома и пытался выбрать более свободный канал. Быстро найти подходящую утилиту под Mac OS X я не смог, поэтому начал её писать на bash. До конца не дописал (хотел ещё обозначить сколько устройств на одном канале висит), то что есть выкладываю — не пропадать же добру! Дальше.
#!/bin/bash
declare -a dots
TEMP=$(mktemp -t `basename "$0"`)
trap "/bin/rm -f $TEMP" EXIT
if [ -z $1 ]; then
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s > $TEMP
else
/bin/cp "$1" $TEMP
fi
# Если название точки содержит пробел, у нас всё поедет, надо избавиться от названия
# для этого мы меряем с каким отступом идёт первая строка (6 — это длина слова SSID, плюс пробелы)
cutname=`awk 'NR==1 {l=length; gsub(/^ +/, ""); print l-length+6}' $TEMP`
# Название будет отрезано командой cut
while read line; do
line=($line)
chs=(${line[2]//,+/ })
# Берём только каналы 2,4ГГц
if [ ${chs[0]} -gt 13 ]; then
continue
fi
# Округляем уровень сигнала
let lvl="(100 + ${line[1]} + 9) / 10"
# Уровень прозрачности верхней линии
let alpha="$lvl*10 - (100 + ${line[1]})"
# Номера каналов
let start="${chs[0]}-2+1"
let end="${chs[0]}+2+${chs[1]:-0}*5+1"
# Набор точек для рисования прямоугольника wifi-точки
for x in $(seq $start $end); do
# Прямоугольник закрашивается сплошным…
for y in $(seq 0 $(($lvl - 1)) ); do
dots[$x+$y*100]=10
done
# Кроме верхней границы, она закрашивается значением
# наибольшей насыщенности
let xy="$x+($y+1)*100"
if [[ -z ${dots[$xy]} || ${dots[$xy]} -lt $alpha ]]; then
dots[$xy]=$alpha
fi
done
# отрезаем заголовок, отрезаем название точки, сортируем по уровню сигнала
done < <(tail -n +2 $TEMP | cut -b${cutname}- | sort -rgk2)
# Блоки по насыщенности границы
blocks=(_ ░ ░ ░ ▒ ▒ ▒ ▒ ▒ ▒ █)
# Цвета вертикальной оси
colors=(32 32 32 32 32 33 33 31 31 31 31)
# Счётчик вертикальной оси
lvl=0
declare -i alpha
# Отрисовка шкалы и данных точек
for y in {10..0}; do
printf "\033[${colors[-$lvl/10]}m% 4d " $lvl
let lvl="$lvl - 10"
for x in {0..15}; do
alpha=${dots[$x+100*$y]}
if [ $alpha -le 0 ]; then
echo -n ' '
else
b=${blocks[$alpha]}
echo -ne "\033[37m$b$b$b"
fi
done
echo
done
# Горизонтальная ось
echo -e "\033[30m -- -- 01 02 03 04 05 06 07 08 09 10 11 12 13"
echo -e "\033[0m"
Алиас для /etc/init.d/… restart
Устал я писать каждый раз строки вида «sudo /etc/init.d/nginx restart» для перезапуска многочисленных серверов, поэтому сделал себе короткий алиас. Я бы не упомянул об этом, если бы не два отличия.
Вот что получилось (у меня это в .bashrc):
rst () { command sudo /etc/init.d/$@ restart; }
function _rst() {
local cur
cur=${COMP_WORDS[COMP_CWORD]}
if [ 1 -eq ${COMP_CWORD} ]; then
COMPREPLY=( $(compgen -f -- /etc/init.d/$cur | xargs -n1 basename -- ) )
else
COMPREPLY=()
fi
}
complete -F _rst rstСколько есть способов восстановить chmod?
Иногда на собеседованиях спрашивают такую задачу, на соображалку: предположим вы случайно сняли права исполнения с команды chmod. Как их восстановить?
Я решил подумать сколько способов исправить эту ситуацию я знаю.
Первый способ — скопировать chmod с соседней машины при помощи scp, sshfs и т. п. Если такая машина имеется, конечно.
Способ второй:
cp /bin/sh ~/chmod2
cat /bin/chmod > ~/chmod2
sudo ~/chmod2 +x /bin/chmod
rm ~/chmod2Третий способ (при условии, что у вас
sudo apt-get --reinstall install `dpkg -S /bin/chmod | cut -f1 -d:`Способ четвёртый:
gcc -x c - <<CHMOD
#include <sys/stat.h>
main(){chmod("/bin/chmod", S_IXUSR | S_IXGRP | S_IXOTH);}
CHMOD
sudo ./a.out
rm a.outКто ещё знает способы?
Кто в офисе?
Побывал сегодня на работе и, в перерыве между делами, написал небольшой скрипт на bash.
На оптимальность решений не претендую, конечно, всё равно основное время работы — это ожидание данных из сокета.
# Кто сегодня в офисе?
# private data vars
WAPIHOST='██████.██████-████.██'
SAPIHOST='█████.██████.██'
SAPI='/█████/██████.xhtml?██████████=█&█████_██=██'
# non-private data vars
WAPI='/where/%s'
NOW=$(date +%s)
function whereAreYou {
exec 3<>/dev/tcp/$WAPIHOST/80
echo -e "GET ${WAPI/\%s/$1} HTTP/1.0\nHost: $WAPIHOST\n\n" >&3
local DATA=$(grep -E '^.?$' -A1 <&3)
if [[ ! $DATA =~ 'VPN' && $DATA =~ 'updated_at' ]]; then
local date=$(echo $DATA | sed -E 's/^.*updated_at"[^"]+"([^"]+).+/\1/' | xargs -Io date -d'o' +%s)
if [ $(($NOW-$date)) -le 3600 ]; then
echo "$1 - $(date -d@$date +%k:%M)"
fi
fi
}
exec 4<>/dev/tcp/$SAPIHOST/80
echo -e "GET $SAPI HTTP/1.0\nHost: $SAPIHOST\n\n" >&4
while read -r line <&4; do
nick=$(echo $line | egrep -o "href='http://$SAPIHOST/\w+" | cut -b$((15+${#SAPIHOST}))-)
[ -n "$nick" ] && whereAreYou $nick
doneКак заменить одну строку на другую в файле (Linux)
Устал я от долгих споров, давайте
Вот несколько способов, которые я знаю.
replace 'hello' 'bye, bye!' -- myfileСамое замечательное, что она умеет менять пары подстрок, что позволяет производить такие замены:
bolk-dev ~ $ echo ABBA | replace A B B A --
BAABВторой способ — создать временный файл, заменить в нём символы или подстроки
T=`/bin/tempfile`
sed 's/hello/bye, bye!/g' myfile > $T
mv $T myfileСразу в тот же файл записывать результат нельзя, операция „>“ сразу же откроет файл на запись и обнулит его. Поможет утилита sponge (входит в пакет moreutils):
sed 's/hello/bye, bye!/g' myfile | sponge myfileОна запишет stdin в файл разом, после того как все данные будут получены.
Добавлено: Азат в комментариях подсказывает, что можно воспользоваться ключом
sed -i 's/hello/bye, bye!/g' myfile