はじめに
i3window-mangerで使われるi3bar(情報を表示するやつ。日時とか)の標準はi3statusです。i3statusは任意の値を表示できないので、多くの人はi3blocks、polybar、conkyのどれかを使っていると思います。私はシンプルなものが好みなのでi3blocksを使っています。
環境
- Arch Linux (5.4.7-arch1-1)
- i3 version 4.17
- i3blocks 1.5
#i3の設定
# 色
set $background #2b303b
set $foreground #c0c5ce
set $secondary #3f4751
set $black #2b303b
set $red #bf616a
set $green #a3be8c
set $yellow #ebcb8b
set $blue #8fa1b3
set $magenta #b48ead
set $cyan #96b5b4
set $white #c0c5ce
bar {
status_command i3blocks
font pango:Hack Regular 10
mode dock
position top
separator_symbol " │ "
workspace_buttons yes
strip_workspace_numbers yes
binding_mode_indicator yes
tray_output none
tray_padding 0
colors {
background $background
focused_background $background
statusline $blue
focused_statusline $blue
separator $secondary
focused_separator $secondary
# 左からborder, bg, fg
focused_workspace $blue $blue $background
active_workspace $background $background $foreground
inactive_workspace $background $background $foreground
urgent_workspace $red $red $background
binding_mode $blue $blue $background
}
}
#i3blocksの設定
項目
- label : 絵文字や項目名など。任意。
- command : 指定したコマンドの標準出力が表示されます。
- color : 16進数で色を指定。色はcommandでも指定できます。未指定なら白。
- interval : 更新間隔。1で1秒。onceでi3blocksを実行したときだけ。repeatやpersistもある。
- signal : シグナルを指定します。i3blocksが指定したシグナルを受信したときに更新されます。
シグナル
音量の表示は、音量を変更したときに更新したいのでシグナルを使います。killやpkillでシグナルを送信します。signal=1
としたならpkill -SIGRTMIN+1 i3blocks
で更新されます。音量を変更するコマンドをどこかのkeyにバインドしていると思うので、その後にpkillを実行するようにします。
bindsym ... && pkill -SIGRTMIN+1 i3blocks
特殊文字
アイコンというか記号というか特殊文字のようなものを、表示したいのならfont awesomeが必要です。
sudo pacman -S awesome-terminal-fonts ttf-font-awesome
設定ファイル
[uptime]
label=
command=uptime | sed 's/.*up \([^,]*\),.*/\1/'
color=#8fa1b3
interval=60
[memory]
label=
command=~/.config/i3blocks/memory.py
#command=free -h | awk 'match($0, /^Mem/){print $3 " / " $2}'
color=#8fa1b3
interval=1
[load average]
label=
command=echo "$(uptime | sed 's/.*load average: \(.*\)/\1/' | cut -d, -f1)/$(grep 'processor' /proc/cpuinfo | wc -l)"
color=#8fa1b3
interval=1
[network]
label=
command=[[ -n $(ip link show up dev wlp4s0) ]] && which wpa_cli &> /dev/null && echo "$({ echo 'status'; echo 'quit'; } | wpa_cli -i wlp4s0 | grep '^ssid=' | cut -d= -f2) : $(cat /proc/net/wireless | tail -1 | tr -s ' ' | cut -d' ' -f4 | sed 's/\./dBm/')"
color=#8fa1b3
interval=1
[lightness]
label=☀
command=xbacklight -get | xargs printf '%.0f%%\n'
color=#8fa1b3
interval=once
signal=2
[volume]
label=
command=~/.config/i3blocks/volume.sh
interval=once
signal=1
[date]
label=
command=date +'%m/%d(%a) %H:%M'
color=#8fa1b3
interval=1
[battery]
command=~/.config/i3blocks/battery.sh
format=json
interval=persist
バッテリー
充電中ならアイコンを順に表示しています。充電中ではないのなら、残量に応じた色とアイコンを表示しています。
#!/usr/bin/env bash
set -euCo pipefail
function online_icon() {
[[ $# -eq 0 ]] && return 1
local -ar icons=('' '' '' '' '')
local index
index=$(expr $1 % ${#icons[@]})
echo ${icons[${index}]}
}
function echo_battery() {
[[ $# -eq 1 ]] \
&& echo -e "\"full_text\": \"$1 \"" \
|| echo -e "\"full_text\": \"$1 \", \"color\": \"$2\""
}
function get_battery() {
[[ -e '/sys/class/power_supply/BAT1/capacity' ]] \
&& cat '/sys/class/power_supply/BAT1/capacity' \
|| echo 0
}
function online() {
[[ $(cat /sys/class/power_supply/ADP1/online) -eq 1 ]] \
&& return 0
return 1
}
function main() {
local -Ar \
high=( ['value']=79 ['icon']='' ['color']='#08d137') \
middle=( ['icon']='' ['color']='#8fa1b3') \
low=( ['value']=21 ['icon']='' ['color']='#f73525')
local online_icon='' cnt=0
while sleep 1; do
cnt=$(expr ${cnt} + 1)
if online; then
online_icon=$(online_icon ${cnt})
else
[[ -z ${online_icon} && $(expr ${cnt} % 60) -ne 1 ]] \
&& continue
online_icon=''
fi
local battery
battery=$(get_battery)
if [[ ${battery} -eq 0 ]]; then
echo_battery ${online_icon}
elif [[ ${battery} -gt ${high['value']} ]];then
echo_battery \
"${online_icon:-${high['icon']}} ${battery}%" ${high['color']}
elif [[ ${battery} -lt ${low['value']} ]];then
echo_battery \
"${online_icon:-${low['icon']}} ${battery}%" ${low['color']}
else
echo_battery \
"${online_icon:-${middle['icon']}} ${battery}%" ${middle['color']}
fi
done
}
main
音量
使用するフォントをHackにしないと■が連結して表示されず、隙間が空いてしまいます。
#!/usr/bin/env bash
set -euCo pipefail
function get_volume() {
pactl list sinks \
| grep 'Volume' | grep -o '[0-9]*%' | head -1 | tr -d '%'
}
function get_muted() {
pactl list sinks \
| grep 'Mute' | sed 's/[[:space:]]//g' | cut -d: -f2 | head -1
}
function to_blocks() {
seq -f '%02g' -s '' 1 5 $1 | sed 's/.\{2\}/■/g'
}
function to_spaces() {
seq -s ' ' $1 5 100 | tr -d '[:digit:]'
}
function to_meters() {
echo "[$(to_blocks $1)$(to_spaces $1)]"
}
function print_volume() {
local -r volume=$(get_volume)
[[ ${volume} -gt 100 ]] \
&& echo -e "${volume}\n" \
|| echo -e "$(to_meters ${volume})\n"
}
function main() {
which pactl &> /dev/null || return 1
LANG=C
print_volume
declare -Ar colors=( ['yes']='#434447' ['no']='#8fa1b3' )
echo "${colors[$(get_muted)]}"
}
main
メモリ
メモリの情報はfreeコマンドで取得できます。しかし、メモリ使用率は取得できません。メモリ使用率とメモリ消費量を人が見やすいように一緒に表示するのが、シェルスクリプトでは面倒だったのでpythonで書いてしまいました。何故かfree -b
、free -h
と2回実行したくありませんでした。
消費量と合計だけを表示するなら、free -h | awk 'match($0, /^Mem/){print $3 " / " $2}'
、
使用率だけを表示するならfree -b | awk 'match($0, /^Mem/){print int($3 * 1000 / $2) / 10}'
で出力可能です。
#!/usr/bin/python3
import os
class MemInfo():
def __init__(self, file_path):
self.info = self.load(file_path)
def load(self, file_path):
if not os.path.exists(file_path):
return {}
with open(file_path, 'r') as mem_info:
return dict(
[line.strip().replace(':', '').split()[0:2]
for line in mem_info.readlines()]
)
def is_loaded(self):
if self.info:
return True
else:
return False
def retrieve(self, target):
return int(self.info[target])
def get_mem_total(self):
return self.retrieve('MemTotal')
def get_mem_free(self):
return self.retrieve('MemFree')
def get_buffers(self):
return self.retrieve('Buffers')
def get_cached(self):
return self.retrieve('Cached')
def get_mem_used(self):
return self.get_mem_total() \
- self.get_mem_free() \
- self.get_buffers() \
- self.get_cached()
# size: kB
def convert(size, cnt):
if size < 1024 ** (cnt+1):
return f'{size / 1024 ** cnt:.3g}{units[cnt]}'
return convert(size, cnt+1)
def main():
mem_info = MemInfo('/proc/meminfo')
if not mem_info.is_loaded():
return
try:
used = mem_info.get_mem_used()
except KeyError as err:
return
rate = used / mem_info.get_mem_total()
try:
print(f'{convert(used, 0)} : {rate:.1%}')
except IndexError as err:
return
units = ['kB', 'MB', 'GB', 'TB']
if __name__ == '__main__':
main()