シェルスクリプト

使ひ方

特定のファイルを開く

#!/usr/bin/bash
# 日記と食事記録のファイルをテキストエディタで開く
gedit ドキュメント/日記.txt ドキュメント/食事記録.txt
#!/usr/bin/bash
# 今月の日記を開く [journal_YYYYMM.html]
gedit journal_`date +%Y%m`.html
#!/usr/bin/bash
# 今月の日記を開く [journal_YYYYMM.html]
SAVE=~/Docs/life
FILE=$SAVE/journal_$(date '+%Y%m').html
MY_TERM=st
EDITOR=kak

# ディレクトリが存在しなければ、ディレクトリとファイルを作成
test -d $SAVE || mkdir -p $SAVE && touch $FILE
# ファイルが存在しなければ、既存のファイルをコピー
test -e $FILE || cd $SAVE && cp "$(ls -c | head -n1)" $FILE
# ファイルを開く
$MY_TERM -e $EDITOR $FILE

特定のファイルを開く(メニュー)

#!/usr/bin/bash
TOC=~/Works/toc.txt
MY_TERM=st
EDITOR=kak

FILE=$(cat $TOC | dmenu -p '開く' -l 10 -fn 'monospace-18' | sed -E 's/^([0-9]+)_.+$/\1/')
if [ "$FILE" ]; then
    case "$FILE" in
        1) FILE=~/Works/cur/現金出納帳.ods ;;
        2) FILE=~/Works/cur/日誌.txt ;;
    esac
    if [[ $(echo "$FILE" | grep -E '\.(txt|md|asciidoc)$') ]]; then
        $MY_TERM -e $EDITOR "$FILE"
    else
        xdg-open "$FILE"
    fi
fi

日附を貼附け

#!/usr/bin/bash
# クリップボードの内容をXセカンダリセレクションに入れる
xclip -selection c -o | xclip -selection s
# 日附の末尾の改行を削除し、クリップボードに入れる
date "+%Y-%m-%d" | tr -d '\n' | xclip -selection c
# 貼附け
xdotool key ctrl+v
# Xセカンダリセレクションの内容をクリップボードに入れる
xclip -selection s -o | xclip -selection c
# Xセカンダリセレクションを空にする
echo | xclip -selection s

ブラウザのアドレスバーにフォーカス

#!/usr/bin/bash
# 変数WINDOWにアクティヴウィンドウの名前を代入
WINDOW=`xdotool getactivewindow getwindowname`
# 変数WINDOWに特定の文字列が含まれてゐるかどうかで条件分岐
if [[ `echo $WINDOW | grep -E 'GNU IceCat$|Tor Browser$'` ]]; then
  # 含まれてゐれば:アドレスバーにフォーカス
  xdotool getactivewindow key --clearmodifiers alt+d
else
  # 含まれてゐなければ:既定の動作(割当ててゐるキー)
  xdotool getactivewindow key --clearmodifiers F2
fi
# 変数WINDOWを削除
unset WINDOW

開いてゐるページのタイトルとURLをコピー

#!/usr/bin/bash
# ブラウザのアドレスバーからURLをコピー
xdotool getactivewindow key --clearmodifiers alt+d ctrl+c Tab
# 変数ADDにURL(クリップボードの内容)を代入
ADD=`xclip -selection c -o`
# 変数TITLEにブラウザウィンドウのタイトルを代入
TITLE=`xdotool getactivewindow getwindowname | sed -E 's/( - )*GNU IceCat$|( — )*Tor Browser$//'`
# 変数SITEINFOにテキストを代入
SITEINFO="${TITLE}
${ADD}"
# テキスト(変数SITEINFO)の末尾の改行を削除し、クリップボードに入れる
echo "$SITEINFO" | head -c -1 | xclip -selection c
# 各変数を削除
unset ADD
unset TITLE
unset SITEINFO
#!/usr/bin/bash
# ブラウザのアドレスバーからURLをコピー
xdotool getactivewindow key --clearmodifiers alt+d ctrl+c Tab
# 変数ADDにURL(クリップボードの内容)を代入
ADD=`xclip -selection c -o`
# 変数TITLEにブラウザウィンドウのタイトルを代入
TITLE=`xdotool getactivewindow getwindowname | sed -E 's/( - )*GNU IceCat$|( — )*Tor Browser$//'`
# 変数LINKにテキストリンク(HTML)を代入
LINK="<a href=\"${ADD}\">${TITLE}</a>"
# テキストリンク(変数LINK)の末尾の改行を削除し、クリップボードに入れる
echo "$LINK" | tr -d '\n' | xclip -selection c
# 各変数を削除
unset ADD
unset TITLE
unset LINK

クリップボード內の文字を置換

#!/usr/bin/bash
# クリップボード内の文字を置換
xclip -selection c -o | sed -e 's/価値/價値/g; s/真実/眞實/g' | xclip -selection c

行頭空け

#!/usr/bin/bash
# クリップボード内の行頭を置換
xclip -selection c -o | sed -E 's/^( +)/★□★\1/g; s/^/ /g; s/^ $//g; s/^ 「/「/g; s/^ 『/『/g; s/^ 【/【/g; s/^ (/(/g; s/^ “/“/g; s/^ 〝/〝/g; s/^ 〔/〔/g; s/^ 《/《/g; s/^ [/[/g; s/^ 〈/〈/g; s/^ ★□★//g' | xclip -selection c

テキストエディタで編輯中の文章をバックアップ

#!/usr/bin/bash
# クリップボードの内容をXセカンダリセレクションに入れる
xclip -selection c -o | xclip -selection s
# 全文をコピー
xdotool getactivewindow key --clearmodifiers ctrl+a ctrl+c click --clearmodifiers 1
# コピーした内容をテキストファイルに保存
xclip -selection c -o > ドキュメント/`date +monokaki_%FT%T.txt`
# Xセカンダリセレクションの内容をクリップボードに入れる
xclip -selection s -o | xclip -selection c
# Xセカンダリセレクションを空にする
echo | xclip -selection s

一行目をタイトルにする

#!/usr/bin/bash
# クリップボードの内容をXセカンダリセレクションに入れる
xclip -selection c -o | xclip -selection s
# 全文をコピー
xdotool getactivewindow key --clearmodifiers ctrl+a ctrl+c click --clearmodifiers 1
# 変数LINEに空白以外の最初の一行を代入
LINE=`xclip -selection c -o | grep -v -E '^( | )*$' | grep -E '.+' | head -n 1 | sed -E 's/\\\/-/g; s/\//-/g; s/\^|\\$|\||\*|\+|\?|\(|\)|\{|\}|\[|\]//g; s/^$/無題/g'`
# コピーした内容をテキストファイルに保存
xclip -selection c -o > ドキュメント/`date +${LINE}_%FT%T.txt`
# Xセカンダリセレクションの内容をクリップボードに入れる
xclip -selection s -o | xclip -selection c
# Xセカンダリセレクションを空にする
echo | xclip -selection s
# 変数LINEを削除
unset LINE

特定のファイルを抽出して開く

タイムスタンプが新しいファイル

#!/usr/bin/bash
# ファイルを検索し、名前順で最後の一行(一番新しいファイル)を抽出
LATEST=`find -name ドキュメント/monokaki_*-*-*T*:*:*.txt | tail -n 1`
# テキストエディタで開く
gedit ${LATEST}
# 変数LATESTを削除
unset LATEST

特定のファイルを檢索して削除

#!/usr/bin/bash
# ファイルを検索し、内容を削除してからファイルを削除
find -name ドキュメント/monokaki_*-*-*T*:*:*.txt -type f -exec sed -i -z -E 's/.|\n//g' {} \; -exec rm {} \;

最新以外のバックアップファイルを削除

#!/usr/bin/bash
# 変数LATESTに最新のファイルを代入
LATEST=`find -name ドキュメント/無題_*-*-*T*:*:*.txt | tail -n 1`
# 変数OLDERに最新以外のファイルを代入
OLDER=`find -name ドキュメント/無題_*-*-*T*:*:*.txt | grep -v ${LATEST}`
# 古いファイルの内容を削除
sed -i -z -E 's/.|\n//g' ${OLDER}
# 古いファイルを削除
rm ${OLDER}
# 各変数を削除
unset LATEST
unset OLDER

指定時間後に音を鳴らす(アラーム)

sleep を利用

  1. #!/usr/bin/bash
    # タイマーの開始を報せる(デスクトップ通知を1秒表示)
    notify-send -t 1000 Set!
    # 30分待機
    sleep 30m
    # 音を鳴らす
    bash ~/timer-alarm-sound.sh
  2. ~/timer-alarm-sound.sh
    #!/usr/bin/bash
    # 通知(a キーで終了)
    echo "〆" `date +%H:%M` | dzen2 -e 'onstart=grabkeys;key_a=exit' -p -h 500 -y 250 -bg '#168e5e' -fg '#effff0' -fn 'GenEi M Gothic v2-50' &
    # 音を鳴らす
    mocp -l /usr/share/sounds/freedesktop/stereo/complete.oga
    # 1秒待機
    sleep 1
    # 音楽の再生を再開
    mocp -p

at を利用

  1. #!/usr/bin/bash
    # 指定時間後にファイルの内容を実行
    at now +30minutes -f ~/timer-alarm-sound.sh
    # タイマーの開始を報せる(デスクトップ通知を1秒表示)
    notify-send -t 1000 Set!
  2. ~/timer-alarm-sound.sh
    #!/usr/bin/bash
    # 通知(a キーで終了)
    echo "〆" `date +%H:%M` | dzen2 -e 'onstart=grabkeys;key_a=exit' -p &
    # 音を鳴らす
    mocp -l /usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga
    # 2秒待機
    sleep 2
    # 音楽の再生を再開
    mocp -p

at を利用(2022年3月26日)

時刻指定

#!/usr/bin/bash
script=$HOME/.config/ShellScript
exec="urxvt -e bash $script/alarm-notify.sh"
time="$(date '+%H:%M' | dmenu -p 'HH:MM' -fn 'monospace-18')"
notify_time_call=8
notify_time_warn=3
notify_geo_call="120x40-125+30"
notify_w_call=120
notify_y_call=38
notify_y_warn=30
notify_bg_call="#168e5e"
notify_bg_warn="#500000"
notify_fg_call="#effff0"
notify_fg_warn="#f0f0f0"
notify_font_call="ChicagoFLF-19"

if [ $time ] && [[ $(echo $time | grep -E '^[0-2][0-9]:[0-5][0-9]$') ]]; then
    min=$(expr \( $(date -d $time '+%s') - $(date -d $(date '+%H:%M') '+%s') \) / 60)
    if [ $min -gt 0 ]; then
        echo -e "$(date '+%H:%M')\n( $min m )\n$time" | dzen2 -e 'onstart=uncollapse' -p $notify_time_call -l 2 -sa c -geometry "$notify_geo_call" -w $notify_w_call -h $notify_y_call -bg "$notify_bg_call" -fg "$notify_fg_call" -fn "$notify_font_call" &
        echo "$exec" | at $time today
    else
        echo "未来の時刻を指定して下さい" | dzen2 -p $notify_time_warn -y $notify_y_warn -bg "$notify_bg_warn" -fg "$notify_fg_warn"
    fi
else
    echo "アラームは設定されませんでした" | dzen2 -p $notify_time_warn -y $notify_y_warn -bg "$notify_bg_warn" -fg "$notify_fg_warn"
fi

アラームを削除

#!/usr/bin/bash
job="$(atq)"
notify_time=2
notify_time_warn=4
notify_y=30
notify_bg_warn="#500000"
notify_fg_warn="#f0f0f0"

if [ "$job" ]; then
    jobnum="$(echo "$job" | sed -E 's/^([0-9]+)\s+(Mon|Tue|Wed|Thu|Fri|Sat|Sun) /\1_/g' | sed -E 's/([0-2][0-9]:[0-5][0-9]):[0-5][0-9]/\1/g' | sed -E 's/( [0-2][0-9]:[0-5][0-9]) [0-9]{4} [\ 0-9a-zA-Z]+$/\1/g' | sed -E 's/(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-3][0-9] //g' | dmenu -p '削除するジョブ' -l 10 -fn 'monospace-18')"
    if [[ $(echo "$jobnum" | grep -E '^([0-9]+)_[0-2][0-9]:[0-5][0-9]$') ]]; then
        jobnum=$(echo "$jobnum" | sed -E 's/^([0-9]+)_[0-2][0-9]:[0-5][0-9]$/\1/')
        atrm "$jobnum" && echo "ジョブを削除" | dzen2 -p $notify_time -y $notify_y
    else
        echo "ジョブは削除されませんでした" | dzen2 -p $notify_time_warn -y $notify_y -bg "$notify_bg_warn" -fg "$notify_fg_warn"
    fi
else
    echo "ジョブはありません" | dzen2 -p $notify_time -y $notify_y
fi

メールを取得・通知

#!/usr/bin/bash
# メールを取得・通知
MAIL_STATUS=`mpop -a | sed -E 's/@.+?(:)/\1/g; s/no messages/0/g; s/new:.+?total: ([0-9]+?) message.+?$/\1/g; s/retrieving message.+?$//g' | sed -zE 's/:\n/: /g; s/\n/ -- /g; s/( -{2} ){2,}/\1/g; s/ -{2} $//g; s/$/\n/g'` && echo "   ${MAIL_STATUS}" | dzen2 -e 'onstart=grabkeys;key_a=exit' -ta l -p -geometry '300x45-305+30' -bg '#afaf5f' -fg '#000000' -fn 'ChicagoFLF' && unset MAIL_STATUS &
#!/usr/bin/bash
# メールを取得・通知
MAIL_STATUS="$(mpop -a | sed -E 's/@.+?(:)/\1/g; s/no messages/0/g; s/new:.+?total: ([0-9]+?) message.+?$/\1/g; s/retrieving message.+?$//g' | sed -zE 's/:\n/: /g; s/\n/ -- /g; s/( -{2} ){2,}/\1/g; s/ -{2} $//g; s/$/\n/g')"
if [ "$MAIL_STATUS" ]; then
    echo "   $MAIL_STATUS" | dzen2 -e 'onstart=grabkeys;key_a=exit' -ta l -p 10 -geometry '300x45-305+30' -bg '#afaf5f' -fg '#000000' -fn 'ChicagoFLF'
else
    echo "メールは取得されませんでした" | dzen2 -p 4 -y 30 -bg '#500000' -fg '#f0f0f0'
fi

キーワードもしくは URL を指定したプログラムで開く

#!/usr/bin/bash
# 置換でエスケープする文字:/&
ws="i3-msg workspace"
ws_pr="Private"
sandbox="firejail --noprofile --hosts-file="~/.blockhosts""
proxy_http="export http_proxy="http://127.0.0.1:8118""
locale="export LC_ALL="C""
timezone="export TZ="UTC""
browser="surf"
browser_class="$browser"
browser_xprop=""_SURF_GO""
brwsr_tor="$HOME/tor-browser_ja/Browser/start-tor-browser"
brwsr_tor_class="Tor Browser"
browser2="badwolf"

input="$(zenity --entry --width=400 --height=20 --text="移動:" --title="移動先を入力" | sed -E 's/(\s){2,}/\1/g; s/^\s//g; s/\s$//g')"
if [ "$input" ]; then
    searchwords="$(echo "$input" | sed -E 's/^(wm|a|hp) (.+)$/\2/g')"
    case "$input" in
        "wm")
            input="https://web.archive.org/" ;;
        "wm "?*)
            input="https://web.archive.org/web/*/$searchwords" ;;
        "man")
            input="https://manpages.debian.org/" ;;
        "man "?*)
            input="https://dyn.manpages.debian.org/jump?q=$searchwords" ;;
        "a")
            input="https://wiki.archlinux.jp/" ;;
        "a "?*)
            input="https://wiki.archlinux.jp/index.php?search=$searchwords&title=%E7%89%B9%E5%88%A5%3A%E6%A4%9C%E7%B4%A2&fulltext=%E6%A4%9C%E7%B4%A2" ;;
        "hp")
            input="https://www.hyperbola.info/packages/" ;;
        "hp "?*)
            input="https://www.hyperbola.info/packages/?q=$searchwords" ;;
        "kiz")
            input="https://kiz.sinumade.net/" ;;
        "valid")
            input="https://validator.w3.org/#validate-by-upload" ;;
    esac
    if [[ $(echo "$input" | grep -E '^https://validator\.w3\.org') ]]; then
        brwsr_tor_wid="$(xdotool search --class "$brwsr_tor_class" | tail -n 1)"
        if [ "$brwsr_tor_wid" ]; then
            brwsr_tor_wid_v="$(xdotool search --onlyvisible --class "$brwsr_tor_class")"
            if [ "$brwsr_tor_wid_v" ]; then
                xdotool windowactivate $brwsr_tor_wid_v && fcitx-remote -c && sleep 0.1 && xdotool key --clearmodifiers ctrl+t type "$input" && xdotool key --clearmodifiers Return
            else
                xdotool windowactivate $brwsr_tor_wid && fcitx-remote -c && sleep 0.1 && xdotool key --clearmodifiers ctrl+t type "$input" && xdotool key --clearmodifiers Return
#               echo "$input" | xclip -selection c && echo "アドレスをコピー" | dzen2 -p 2 -y 30 -h 30
            fi
        else
            $sandbox $brwsr_tor "$input"
        fi
    elif [[ $(echo "$input" | grep -E '^https://(web\.archive\.org|h-node\.org)') ]]; then
        $ws $ws_pr && $locale && $timezone && $proxy_http && firejail --noprofile $browser2 "$input"
    else
        echo "$input" | grep -E '^[^ :/]+\.[^ ]+$' && input="$(echo "$input" | sed -E 's/^(.+)$/https:\/\/\1/g')"
        echo "$input" | grep -E '^gemini://' && input="$(echo "$input" | sed -E 's/^gemini:\/\//https:\/\/portal.mozz.us\/gemini\//g')"
        echo "$input" | grep -E '^gopher://' && input="$(echo "$input" | sed -E 's/^/https:\/\/gopher.floodgap.com\/gopher\/gw?/g')"
        echo "$input" | grep -E '^https*://' || input="$(echo "$input" | sed -E 's/^/https:\/\/www.mojeek.com\/search?q=/g')"
        $proxy_http && $sandbox $browser "$input" # フォーカスのあるウィンドウで開く場合は、この行を削除して以下をアンコメント
#       browser_wid="$(xdotool search --onlyvisible --class "$browser_class")"
#       wid="$(xdotool getactivewindow)"
#       if [[ $(echo "$browser_wid" | grep -E "$wid") ]]; then
#           xprop -id $wid -f $browser_xprop 8s -set $browser_xprop "$input"
#       else
#           $proxy_http && $sandbox $browser "$input"
#       fi
    fi
fi

ハードウェアの情報を取得

#!/usr/bin/bash
SAVE=/tmp/lshw.txt

sudo lshw | xclip -selection p && \
test -e $SAVE && chmod 644 $SAVE ; \
xclip -selectio p -o | grep 'description' | sed -E 's/^\s{4}//g; s/\s{3}/ - /g; s/description:\s//g' | \
sed '1i ============ TOC ============' | \
sed '$a ============ /TOC ============\n' > $SAVE && \
xclip -selection p -o >> $SAVE && \
chmod 444 $SAVE ; \
$MY_TERM -e $EDITOR $SAVE
#!/usr/bin/bash
SAVE=/tmp/hwinfo.txt

sudo hwinfo | grep -A 2000 'end debug info' | xclip -selection p && \
test -e $SAVE && chmod 644 $SAVE ; \
xclip -selectio p -o | grep -E '^[0-9]+:' | sed -E 's/^([0-9]+: )[a-zA-Z]+ [0-9a-z\.]+: [0-9]{4,5} /\1/g' | \
sed '1i ============ TOC ============' | \
sed '$a ============ /TOC ============\n' > $SAVE && \
xclip -selection p -o | sed '/end debug info/d' >> $SAVE && \
chmod 444 $SAVE ; \
$MY_TERM -e $EDITOR $SAVE

スクリーンショットを撮影し、參照

#!/usr/bin/bash
SAVE=/tmp/screenshots

# ファイルの参照に変数を利用
#test -d $SAVE || mkdir -p $SAVE ; cd $SAVE && scrot '%Y-%m-%d_%H%M%S_$wx$h.png' && SAVE="$SAVE/$(ls -c $SAVE | head -n1)" && mupdf $SAVE
test -d $SAVE || mkdir -p $SAVE ; cd $SAVE && scrot '%Y-%m-%d_%H%M%S_$wx$h.png' -e 'mupdf $f'

電卓

#!/usr/bin/bash
SAVE=/tmp/calc.txt
WIN_W=300
WIN_H=110
EXP_TTL="電卓"
EXP_MSG="式:"
ANS_TTL="計算結果"
QST_MSG="式のエラーかも?:"

EXP="$(zenity --entry --text="$EXP_MSG" --title="$EXP_TTL" --width=$WIN_W --height=$WIN_H)"

while [ "$EXP" ]; do
    ANS=$(echo "scale=3; $EXP" | bc | sed -E 's/^(-{0,1})(\.)/\10\2/; s/\.0{3}$//; s/(\.[1-9]{1,2})0{1,2}$/\1/g; /\.[0-9]{4,}/s/(\.[1-9]{3})[0-9]+/\1/')
    if [[ $(echo $ANS | grep -E '^-{0,1}[\.0-9]+$') ]]; then
        if [[ $(echo $ANS | grep -E '[0-9]{4,}') ]]; then
            ANS=$(echo $ANS | sed -E 's/([0-9]{3})(\.[0-9]{1,3})*$/,\1\2/')
            while [[ $(echo $ANS | grep -E '[0-9]{4,}') ]]; do
                ANS=$(echo $ANS | sed -E 's/([0-9]{3},)/,\1/')
            done
        fi
        test -e $SAVE && chmod 644 $SAVE
        echo -e "\n$EXP\n= $ANS" >> $SAVE
        chmod 444 $SAVE
        EXP="$(zenity --entry --text="$EXP\n= $ANS" --entry-text="$(echo $ANS | sed 's/,//g')" --title="$ANS_TTL" --width=$WIN_W --height=$WIN_H)"
    else
        # 四則演算以外の解を記録しない
#        test -e $SAVE && chmod 644 $SAVE
#        echo -e "\n$EXP\n= $ANS" >> $SAVE
#        chmod 444 $SAVE
        EXP="$(zenity --entry --text="$QST_MSG\n$EXP\n= $ANS" --entry-text="$(echo $ANS | sed 's/,//g')" --title="$ANS_TTL" --width=$WIN_W --height=$WIN_H)"
    fi
done