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
ソフトウェアエンジニアの技術ブログ:Software engineer tech blog
随机应变 ABCD: Always Be Coding and … : хороший
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
シェルで引数を
#!/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)
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/ に対象フォルダがないぞ…
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
インストール関連はシェルで書いて、テストもシェルで書くのね。なるほど、勉強になりますね。
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は標準入力から受け取った内容を、標準出力とファイルに書き出すコマンド
#!/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
文字列を評価、連結して実行する
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は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
他にも色々使い方ができる
取り敢えず置換ができると覚えておく
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の入力は同じか…
test.py
print("hello")
test.sh
#!/bin/bash python3 test.py sleep 5s python3 test.py
$ chmod +x test.sh
$ ./test.sh
hello
hello
なるほど、自動化できるな。