【Shell】ファイルを生成

ジェネシスブロックを生成するシェルを作ります。

#!/bin/bash

echo "{\"time\":\"0000-00-00 00:00:00.000000000 UTC\",\"transactions\":[],\"hash\":\"genesisblockhash\",\"nonce\":\"0\"}" > data/blocks.txt

$ ./setup.sh

// blockを生成

data/blocks.txt

{"time":"0000-00-00 00:00:00.000000000 UTC","transactions":[],"hash":"genesisblockhash","nonce":"0"}
{"time":"2025-01-05 01:43:43.528815824 UTC","transactions":[{"time":"2024-12-25 22:53:36.824066840 UTC","sender":"5bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991123","receiver":"4bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991124","amount":10,"signature":"8000E340A55A517D0F27F3A63FBE39ED576BA491DFAC89B44654AB147EC66B206B054BAAF53E318EB2721DC892B4736630F400547989AE9F7C069034ECB4DF98"},{"time":"2024-12-25 22:53:36.824066840 UTC","sender":"4bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991123","receiver":"4bac6cb0f4ad6397752c3d73b88c5c86e3d88ac695118494a1732e2abd16c76acad3d6586c37c8db7e69c2f812f99275198936957d72c38d71981991124","amount":10,"signature":"8000E340A55A517D0F27F3A63FBE39ED576BA491DFAC89B44654AB147EC66B206B054BAAF53E318EB2721DC892B4736630F400547989AE9F7C069034ECB4DF98"}],"hash":"00006059ac7bd5ea2ece1428c90c402c602cf402b0483e7063dfa4f3e58c7ae4","nonce":"215835"}

ちゃんと改行されていますね。echoのテキストの最後に\nを入れなくても大丈夫でした。
genesis blockとblockの生成までできました。
続いて、verify chainの関数を作って、ブロックが正しく生成されているか確認した上で、minerへの報酬トランザクションを生成する関数を作りたい。

【shell】基礎から立ちかえる3

function test_func() {
    local var1
    var1=aaa

    local var2=bbb
}
function echo_self_args()
{
    echo $1
    echo "$2"
    echo ${3}
    echo "${4}"
    echo $#
    echo "$@"
}

echo_self_args arg1 arg2 'arg3 arg4' arg5
function echo_value1()
{
    local var1=local1
    echo ${FUNCNAME[0]} ':$var1:1' $var1

    echo ${FUNCNAME[0]} ':$var2:1' $var1
}

function echo_value2()
{
    local var1=local2
    echo ${FUNCNAME[0]} ':$var1:1' $var1

    local var2=local2
    echo ${FUNCNAME[0]} ':$var2:1' $var1

    echo_value1
    echo ${FUNCNAME[0]} ':$var1:1' $var1
    echo ${FUNCNAME[0]} ':$var2:1' $var1
}

var1=global
echo 'global :$var1:1:' $var1
echo 'global :$var2:1:' $var2

echo_value2
echo 'global :$var1:2:' $var1
echo 'global :$var2:2:' $var2
function return_test()
{
    if [[ -z $1 ]]; then
        echo 'arg1 is empty.'
        return 1
    fi

    echo $1
}

return_test test
echo '終了ステータス': $?
echo ---
return_test 
echo '終了ステータス': $?
echo 'Hello' > hello.txt
ls /bin /error > bin.txt 2> error.txt
ls /bin /error &> result.txt
tr hoge fuga < hoge.txt
var1=value
text=$(cat << EOF
    arg1: $1
    var1: $var1
EOF
)
echo "$text"
echo first message1 > output.txt
echo second message1 >> output.txt
echo third message1 >> output.txt

{
    echo first message2
    echo second message2
    echo third message2
} > output.txt

{ echo first message3;echo second message3;echo third message3; } > output.txt
cd /bin
pwd
var1=value1
echo $var1

(
    cd /home/vagrant
    pwd
    echo $var1
    var1=value2
    echo $var1
)

pwd
echo $var1
set -e

ls /error
mkdir /error/dir1
set -u

rm -rf $work_dir/
set -C

touch test1.txt
echo "aaa" >| test1.txt
echo "bbb" >> test1.txt

touch test2.txt
echo "ccc" > test2.txt

【shell】基礎から立ちかえる2

array=(item1 item2 'item3 item4' item5)

echo '${array[0]}': ${array[0]}
echo '${array[1]}': ${array[1]}
echo '${array[2]}': ${array[2]}
echo '${array[3]}': ${array[3]}
array=(item1 item2 'item3 item4' item5)

echo ${#array[@]}
array=(item0 [2]=item2 [4]=item4)

echo ${#array[@]}
echo ${array[0]}
echo ${array[1]}
echo ${array[2]}
echo ${array[3]}
echo ${array[4]}
echo ------------------

array[1]=item1
array[2]=
echo ${#array[@]}
echo ${array[0]}
echo ${array[1]}
echo ${array[2]}
echo ${array[3]}
echo ${array[4]}
echo ------------------
array=(item1 item2 'item3 item4' item5)

function echo_array_items() {
    echo $1
    echo $2
    echo $3
    echo $4
    echo $5
    echo ------------------------
}

echo Use '"${array[@]}"'
echo_array_items "${array[@]}"

echo Use '"${array[*]}"'
echo_array_items "${array[*]}"

echo Use '${array[@]}'
echo_array_items ${array[@]}

echo Use '${array[*]}'
echo_array_items ${array[*]}
array=(item1 item2 item3)
echo "${array[@]}"

array2=(item_a item_b "${array[@]}")
echo "${array2[@]}"

array3=("${array[@]}" item_c item_d)
echo "${array3[@]}"

array+=(item_e item_f)
echo "${array[@]}"
array=(item0 [2]=item2 [4]=item4)
echo "${!array[@]}"
if grep -n test test.txt; then
    echo $?
    echo success
else
    echo $?
    echo fail
fi
test "$1" = "test"
echo 'test コマンドの終了ステータス': $?

["$1" = "test"]
echo '[ コマンドの終了ステータス':$?

if ["$1" = "test"]; then
    echo success
else
    echo fail
fi
if [ \( "$1" = "a" -o "$2" = "b" \) -a -f test.txt ]; then
    echo '第一引数がaまたは第二引数がbで、かつtest.txtが存在しています'
fi
if [[ ("$1" = "a" || "$2" = "b" ) && -f test.txt ]]; then
    echo '第一引数がaまたは第二引数がbで、かつtest.txtが存在しています'
fi
var=$1
if [[ $var = 'hoge fuga' ]]; then
    echo success
else
    echo fail
fiv
case "$file" in
    *.csv)
        echo this is csv
        ;;
    special-* | important-*)
        echo this is special file
        ;;
    *)
        echo "Invalid file: $file"
esac
for arg in "$@"; do
    echo $arg
done
array=(aaa 'bbb ccc' ddd)
for element in "${array[@]}"; do
    echo $element
done
while [[ $# -gt 0 ]]; do
    echo $1
    shift
done
until [[ $# -eq 0 ]]; do
    echo $1
    shift
done

【shell】基礎から立ちかえる1

#!/bin/bash

echo 'hello world!'

$ chmod +x stest.sh
$ ./stest.sh
hello world!

#!/bin/bash

echo 'hello world!'
pwd
echo \
    'I' \
    'love' \
    'shell' \
    'script' \
echo
'End world!'
#!/bin/bash

var='value'
echo $var

var='change'
echo $var
#!/bin/bash

readonly var='value'
var='fuga'
var='set'
echo $var
unset var
echo $var
var=value
echo $var
var='hoge fuga'
echo $var
var=hoge fuga
echo $var
empty=''
echo \$empty: $empty
empty=
echo \$empty: $empty
echo \$undefined: $undefined
var=value
echo $var
echo \$var
echo \$var $var
echo \\

var=hoge\ fuga
echo $var
var1=value
var2='${var1}'
echo $var2
var1=value
var2="${var1}"
echo $var2
var1='hoge''fuga'
echo '$var1': $var1

var2=hoge
var3=$var1$var2
echo '$var3': $var3

echo "\$var1hoge": $var1hoge
echo "\$var1'hoge'": $var1'hoge'
echo "\${var1}hoge": ${var1}hoge
echo "\${var1}'hoge'": ${var1}'hoge'
echo '$1': $1
echo '${1}': ${2}
echo '"$3"': "$3"
echo '${10}': ${10}
echo '${11}': ${11}
echo '$10': $10
echo $0
echo $1
echo '入力値' $1
exit $1
echo ----------
echo 引数の数 $#
echo '$1'の値 $1
echo '$2'の値 $2
shift
echo $?
echo ----------
echo 引数の数 $#
echo '$1'の値 $1
echo '$2'の値 $2
shift
echo $?
echo ----------
echo 引数の数 $#
echo '$1'の値 $1
echo '$2'の値 $2
shift
echo $?
echo ----------
function echo_args() {
    echo '引数の数' $#
    echo '$1'の値 $1
    echo '$2'の値 $2
    echo '$3'の値 $3
    echo ----------
}

echo '"$@"'の場合
echo_args "$@"
echo '"$*"'の場合
echo_args "$*"
echo $$

(sleep 10; echo 'end') &
echo $!
wait $!

[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