[Shell] set -eとは

set -e とはコマンドの実行結果がエラー(= 終了ステータスが 0 以外)になった時にシェルスクリプトを自動的に中断させる機能
条件文(&& や || を含む)と共に使うシェル関数は set -e の効果が無効になる

contrib/devtools/split-debug.sh.in

set -e
if [ $# -ne 3 ];
    then echo "usage: $0 <input> <stripped-binary> <debug-binary>"
fi

[shell] manページを作ろう

シェルで引数を

#!/bin/bash

if [ $# -ne 2 ]; then
    echo "指定された引数は$#個です。" 1>&2
    echo "実行するには2個の引数が必要です。" 1>&2
    exit 1
fi

cat <<__EOT__
指定された引数は、
    $1
    $2
の$#個です。
__EOT__

exit 0

上記をベースに、引数で表示するmanを変えていきます。caseで引数に応じて出し分ける。

#!/bin/bash

output() {
    case $1 in
        "daemon")
                cat <<__EOT__
            NAME daemon
            SYNOPOIS A program that resides in main memory and provides specific functions
__EOT__
    exit 0 ;;
            
        "cli")
                cat <<__EOT__
            NAME cli
            SYNOPOIS A text-based interface that allows you to enter commands to interact with your computer's operating system
__EOT__
    exit 0 ;;   
    esac
}

if [ $1 == "man" ]; then
    if [ $# -ne 2 ]; then
        echo "Please enter arguments after man." 1>&2
        exit 1
    else
        output $2
    fi
fi

$ ./test.sh man daemon
NAME daemon
SYNOPOIS A program that resides in main memory and provides specific functions
$ ./test.sh man cli
NAME cli
SYNOPOIS A text-based interface that allows you to enter commands to interact with your computer’s operating system

gen-manpage.pyだと、コンテンツは別ページに持っているようです。topディレクトリにディレクトリ名を繋げて参照しています。
os.getenvは環境変数を持ってくる

import os
import subprocess
import sys
import tempfile

BINARIES = [
'src/bitcoind',
'src/bitcoin-cli',
'src/bitcoin-tx',
'src/bitcoin-wallet',
'src/bitcoin-util',
'src/qt/bitcoin-qt',
]

# Paths to external utilities.
git = os.getenv('GIT', 'git')
help2man = os.getenv('HELP2MAN', 'help2man')

# If not otherwise specified, get top directory from git.
topdir = os.getenv('TOPDIR')
if not topdir:
    r = subprocess.run([git, 'rev-parse', '--show-toplevel'], stdout=subprocess.PIPE, check=True, text=True)
    topdir = r.stdout.rstrip()

# Get input and output directories.
builddir = os.getenv('BUILDDIR', topdir)
mandir = os.getenv('MANDIR', os.path.join(topdir, 'doc/man'))

# Verify that all the required binaries are usable, and extract copyright
# message in a first pass.
versions = []
for relpath in BINARIES:
    abspath = os.path.join(builddir, relpath)
    try:
        r = subprocess.run([abspath, "--version"], stdout=subprocess.PIPE, check=True, text=True)
    except IOError:
        print(f'{abspath} not found or not an executable', file=sys.stderr)
        sys.exit(1)
    # take first line (which must contain version)
    verstr = r.stdout.splitlines()[0]
    # last word of line is the actual version e.g. v22.99.0-5c6b3d5b3508
    verstr = verstr.split()[-1]
    assert verstr.startswith('v')
    # remaining lines are copyright
    copyright = r.stdout.split('\n')[1:]
    assert copyright[0].startswith('Copyright (C)')

    versions.append((abspath, verstr, copyright))

if any(verstr.endswith('-dirty') for (_, verstr, _) in versions):
    print("WARNING: Binaries were built from a dirty tree.")
    print('man pages generated from dirty binaries should NOT be committed.')
    print('To properly generate man pages, please commit your changes (or discard them), rebuild, then run this script again.')
    print()

with tempfile.NamedTemporaryFile('w', suffix='.h2m') as footer:
    # Create copyright footer, and write it to a temporary include file.
    # Copyright is the same for all binaries, so just use the first.
    footer.write('[COPYRIGHT]\n')
    footer.write('\n'.join(versions[0][2]).strip())
    footer.flush()

    # Call the binaries through help2man to produce a manual page for each of them.
    for (abspath, verstr, _) in versions:
        outname = os.path.join(mandir, os.path.basename(abspath) + '.1')
        print(f'Generating {outname}…')
        subprocess.run([help2man, '-N', '--version-string=' + verstr, '--include=' + footer.name, '-o', outname, abspath], check=True)

fish shell入門

ubuntu22.04にインストールします。

$ sudo apt-add-repository ppa:fish-shell/release-3
$ sudo apt update
$ sudo apt install fish
$ fish –version
fish, version 3.7.0

~/.config/ に対象フォルダがないぞ…

[shell] テストコマンドを書く

test -e auto_update.sh; echo $?

FILE="auto_update.sh"
if test -n "$FILE"; then
    echo "File is exist"
fi

$ sh test.sh
0
File is exist

インストール関連はシェルで書いて、テストもシェルで書くのね。なるほど、勉強になりますね。

[shell] Ubuntuのupdate処理を自動化

auto_update.sh

#!/bin/bash

today=$(date "+%Y%m%d")

log_DIR="./update_log"
log_FILE="./update_log/update_${today}.log"

if [! -d $log_DIR]; then
    sudo mkdir ${log_DIR}
fi

if [ ! -e $log_FILE ]; then
    sudo touch ${log_FILE}
fi

all_update(){
    sudo apt-get update -y
}

start_time=$(date '+%Y/%m/%d %T')

echo "#### $start_time start update ####" | sudo tee -a ${log_FILE}

all_update | sudo tee -a ${log_FILE}

end_time=$(date '+%Y/%m/%d %T')

echo "#### $end_time end update ####" | sudo tee -a ${log_FILE}

$ chmod 777 auto_update.sh
$ ls -a
. .. auto_update.sh update_log
$ sh auto_update.sh

teeは標準入力から受け取った内容を、標準出力とファイルに書き出すコマンド

shell scriptでメモリ使用率

#!/bin/bash

YMD=`date +"%Y/%m/%d %p %I:%M:%S"`

MEM_LOG="memory.log"

MEM_USED=`free | grep Mem | awk '{print($2-$3)/$2*100}'`
SWAP_USED=`free | grep Swap | awk '{print($3)/$2*100}'`

echo "$HOSTNAME memory is $MEM_USED %, date is $YMD" >> MEM_LOG
echo "$HOSTNAME swap is $SWAP_USED %, date is $YMD" >> MEM_LOG

vagrant memory is 86.4592 %, date is 2023/10/21 PM 07:25:24
vagrant swap is 4.532 %, date is 2023/10/21 PM 07:25:24

[Linux] evalとは

文字列を評価、連結して実行する

hoge.txt

hoge hoge

fuga.txt

fuga fuga fuga

example.sh

#!/bin/bash
value='hoge'

#文字列としてコマンドを変数に格納
cmd='grep $value hoge.txt'
echo $cmd
eval $cmd

$ sh example.sh
grep $value hoge.txt
hoge hoge

#!/bin/bash

grep_text() {
	for txt_file in $(ls . | grep ".txt$"); do
		grep_result=$(grep $1 $txt_file)
		if [ $? -eq 0 ]; then
			eval echo $2
		fi
	done
}

query='hoge'
message='検索対象が見つかりました。見つかったファイル名:$txt_file'
grep_text $query "${message}"

query='fuga'
message='検索対象が見つかりました。見つかったファイル名:$grep_result'
grep_text $query "${message}"

$ sh success.sh
検索対象が見つかりました。見つかったファイル名:hoge.txt
検索対象が見つかりました。見つかったファイル名:fuga fuga fuga

何これ、やればやるほど次から次へと課題が出てくる

sedコマンド

文字列を全置換したり行単位で抽出したり、削除したり、テキスト処理できるコマンド
コマンドラインパラメータで指定して非対話的に一括処理もできる
sedはStream EDitorの略

### sedの構文
sed OPTIONS… [SCRIPT] [INPUTFILE…]
[SCRIPT]とは “s/foo/bar/g”
“-e”オプションで直後に[SCRIPT]が来る

$ echo “Tech Blog” | sed -e “s/Blog/Comment/g”
Tech Comment
$ echo “Tech Blog” | sed -e “s/ /-/g”
Tech-Blog

バックスラッシュはエスケープ
$ echo “Tech Blog” | sed -e “s/ /\!/”
Tech!Blog

二つ目に見つかった”o”を”_”に変換
$ echo “Hello World” | sed -e “s/o/__/2”
Hello W__rld

### ファイルの書き換え
$ echo “Hello World” > sample.txt
$ sed -e “s/World/Coffee/g” sample.txt
Hello Coffee
$ cat sample.txt
Hello World
$ sed -i -e “s/World/Shinbashi/g” sample.txt
$ cat sample.txt
Hello Shinbashi

他にも色々使い方ができる
取り敢えず置換ができると覚えておく

シェル・FTP接続でファイル転送する方法

putでファイルを転送し、getでファイルを取得する

### コマンドラインでSFTP接続する方法
$ sftp ubuntu@***.**.**.**
sftp> put sample.txt
Uploading sample.txt to /home/ubuntu/sample.txt
sample.txt 100%

### シェルでSFTPする方法
test.shにファイルの転送、取得を書いて、sample.shにftp接続する際のパスワードを書きます。
$ chmod +x test.sh
$ chmod +x sample.sh

test.sh

sftp ubuntu@***.**.***.** << END
get nodesource_setup.sh
put sample.txt
quit
END

sample.sh

#!/bin/bash
expect -c "
  set timeout 3
  spawn ./test.sh
  expect \"ubuntu@***.**.***.**'s password:\"
  send \"hogehoge\n\"
  interact
"

$ ./sample.sh
spawn ./test.sh
ubuntu@***.**.***.**’s password:
Connected to ***.**.***.**.
sftp> get nodesource_setup.sh
Fetching /home/ubuntu/nodesource_setup.sh to nodesource_setup.sh
/home/ubuntu/nodesource_setup.sh 100% 14KB 345.7KB/s 00:00
sftp> put sample.txt
Uploading sample.txt to /home/ubuntu/sample.txt
sample.txt 100% 4 0.3KB/s 00:00
sftp> quit

ほう、これがやりたかった。

sftp ubuntu@hoge.com としてもできるが、passwordの入力は同じか…