#author("2026-04-20T23:32:07+00:00","default:sysosa","sysosa") #author("2026-04-20T23:39:49+00:00","default:sysosa","sysosa") 結構簡単なbashスクリプトを作っているが、細かい点を忘れがちでここに記す &size(10){もはやbashに関係ないものも書いているが..}; ***ホスト毎に実行スクリプトを変更する [#hdbe1b0a] #code(nonumber){{ [ -f /bin/hostname ] && host=`/bin/hostname -s` case "$host" in "em00"|"em01"|"em02") source /home/Common/cpu.sh ;; "g01"|"g02"|"g03") source /home/Common/gpu.sh ;; esac unset host }} ***cronでの多重起動防止 - pidof を使う [#vec6b673] 例えばrsyncの多重起動を防止したいとして下記のようにします. #code(nonumber){{ [root@c ~]# cat backup_AtoB.bash #!/bin/bash /usr/bin/rsync -av --delete \ --log-file=/root/log/rsync-`date +"%Y%m%d%H%M%S"`.log \ /home root@destination:/backup/home/ [root@c ~]# crontab -e MAILTO="" 0 23 * * * /usr/sbin/pidof -x backup_AtoB.bash >/dev/null || /root/backup_AtoB.bash >> /root/backup_AtoB.bash.log [root@c ~]# }} 説明としてはスクリプト「backup_AtoB.bash」プロセス番号を探して掲示します. 「||」で繋いでいるので、前段(/usr/sbin/pidof -x backup_AtoB.bash >/dev/null)が失敗したら、後段(/root/backup_AtoB.bash >> /root/backup_AtoB.bash.log)を実行します 前段の失敗とはそのようなプロセスがない. つまりは「backup_AtoB.bash」プロセスが存在しないことを意図します. 「backup_AtoB.bash」プロセスが存在していれば、「||」の後段には進みません スクリプト名で判断するので同じ名前のスクリプトが走っていると誤作動するかも. ***cronでの多重起動防止 - touch を使う [#l810f7e7] もっと簡単な転送方法としては下記スクリプトを cron に噛ませます #code(nonumber){{ #!/bin/bash # mount先を持っているか確認して # mount先を確認するなら. (リモート越しのrsyncなら不要) if [ ! -f "/OffloadData/_offloaddata_" ]; then exit fi # 実行中確認ファイルを確認して if [ -f "/root/script/run" ]; then exit else touch /root/script/run fi # tiffファイルの転送なら /usr/bin/rsync -av --delete --include="*/" --include="*.tiff" --include="*.gain" --exclude="*" \ /OffloadData/ /ceph/OffloadData/ \ --log-file=/root/script/log/rsync-`date +%Y%m%d-%H%M`.log # ssh でアクセス可能なフォルダで所有者、フォルダモードを変更して転送なら /usr/bin/rsync -rltDvog --chown=cryoem:cryoem --chmod=F440,D550 -e "ssh -i /root/script/id/qnap-connection" \ # ssh でアクセス可能なフォルダで所有者、パーミッションをファイルは644,フォルダは755に変更して転送なら /usr/bin/rsync -rltDvog --chown=cryoem:cryoem --chmod=F644,D755 -e "ssh -i /root/script/id/qnap-connection" \ access-user@camera:/CameraServer/ /ceph/CameraServer/ \ --exclude '@Recycle' --exclude '.@__thumb' --ignore-errors \ --log-file=/root/script/log/rsync-`date +%Y%m%d-%H%M`.log /bin/rm -f /root/script/run }} ***parallel [#x2a7f710] &color(white,blue){注意}; CentOSにはパッケージ[moreutils-parallel.x86_64]と[parallel.noarch]があります ■[moreutils-parallel.x86_64]なら #code(nonumber){{ parallel [option] [実行コマンド] -- [引数(変数かな?)] 例: [saber@c Movies]$ parallel -j3 -i relion_convert_to_tiff --compression zip --deflate_level 9 --i {} -- *.mrc -jはパラレル数 -iは引数の結果を{}で代用する }} ■[parallel.noarch](通称「GNU Parallel」)なら #code(nonumber){{ (--dry-runで確認) [saber@c Movies]$ ls *.mrc | parallel --dry-run relion_convert_to_tiff --compression zip --deflate_level 9 --i {} (実行) [saber@c Movies]$ ls *.mrc | parallel relion_convert_to_tiff --compression zip --deflate_level 9 --i {} }} 「-j」で同時実行数を決められるが、何も指定しないとthreads数で投げしてくれる ***8には注意 [#e07ec029] #code(nonumber){{ a="0008" echo $(($c)) }} を実行すると「行 2: 0008: 基底の値が大きすぎます (エラーのあるトークンは "0008")」と言われる。 #code(nonumber){{ a="0008" echo $((10#$c)) }} と修正すればok ***ファイルの存在が確認できたら実行する [#uac9ae7a] 前段での処理が完了して、その出力ファイルの存在を確認したら次のステップへ進ませる #code(nonumber){{ until [ -r Micrographs/$seqfile ] ; do sleep 1; done }} ***findで見つけたファイルをtarで固める [#qbe4e528] #code(nonumber){{ tar . -name \( '*.html' -o -name '*.htm' \) -print0 | tar czf find.tar.gz --null -T - }} ***繰り返して実行する [#ff29081c] #code(nonumber){{ while true ;do echo `date '+%y%m%d %H%M%S'` $(sensors | head -n +3 | tail -n 1 ); sleep 10; done; while true; do echo `date '+%y%m%d %H:%M:%S'` $(smartctl -d scsi -a /dev/nvme0n1 -T permissive | grep "Current Drive"|awk '{print $4}'); sleep 10 ;done; }} ***pidに関係するファイルをみる [#u6ab1dc0] #code(nonumber){{ lsof -p <pid> watch -n 2 lsof -p <pid> <-- 2秒ごとにlsofの内容を表示する }} ***○行目以降を表示 [#qe043658] qstatの表示で上二行を省いて表示 #code(nonumber){{ qstat | tail -n +3 }} ***ヒアドキュメント [#z3050ec6] #code(nonumber){{ cat << _EOF_ > README.1st どうして こうなった? _EOF_ }} 変数に収めるなら #code(nonumber){{ l=$(cat <<_EOF_ どうしても こうなる _EOF_ ) #改行して「)」を入れる }} ***awk [#j1584250] awkをbashで使ったので unixユーザで、uidが1000以上のユーザリストを取得する #code(nonumber){{ [foo@c ~]$ getent passwd |awk -F: '$3>1000{print $1}' }} 「-F」はデミリタ、「$3」でUIDの部分を示してそれが1000より大きいのを持って来て、「{print $1}」でアカウント名を表示 ***標準出力 [#y14c8556] 標準出力、標準エラー共に一つのファイルに入れる. 「&color(magenta){2>1&};」を使う #code(nonumber){{ [foo@c ~]$ ./bash.cmd > log 2>&1 }} &size(10){他にも「./bash.cmd &color(crimson){>&}; log」、「./bash.cmd &color(crimson){&>}; log」}; 共に出力しないなら「&color(magenta){2>1&};」と「&color(mediumvioletred){/dev/null};」を使って #code(nonumber){{ [foo@c ~]$ ./bash.cmd > /dev/null 2>&1 }} どちらとも別々のファイルに入れたい. log1(標準出力)、log2(標準エラー) #code(nonumber){{ [foo@c ~]$ ./bash.cmd 1> log1 2> log2 }} 標準エラーは画面に出しつつファイルにも書いて欲しい。標準出力はいらね. &color(magenta){tee};コマンドは標準出力をファイルに落としてくれるが、標準エラーは見ない。 なので一旦エラーの識別子(2)を(1)に変更して、パイプ(|)で渡す #code(nonumber){{ [foo@c ~]$ { ./bash.cmd 3>&2 2>&1 1>&3 | tee log1; } 2> /dev/null }} &color(white,blue){留意}; 先頭の「&color(red){''{''};」の後は空白が必要 「3>&2 2>&1 1>&3」の考え方だけど、1と2を入れ替えただけ。イメージは下記のような感じ &ref(2017y08m23d_190145715.png,nolink); 最終的に1と2が入れ替わった ***for文 [#i4cebc24] よく使います. フォルダ内のファイルを処理したい場合 #code(nonumber){{ #!/bin/bash IFS=$'\n' # IFS="$'\n'$'\t' " デフォルト値だと改行、タブ、スペースが区切りと見做される for f in `ls /tmp`; do echo $f done }} そのフォルダが複数ある場合 #code(nonumber){{ #!/bin/bash etc=`ls -d /etc/*` #/etc直下のファイルをフルパスで表記 tmp=`ls -d /tmp/*` #同/tmp直下も for f in $etc $tmp; do # 2つの変数を同時に扱う echo $f done }} 特定のファイルで #code(nonumber){{ #!/bin/bash mrcs=$(find /data4 -type f -name "*.mrcs" | grep -e "[0-9]\{4\}_[0-9]\{2\}") # "2012_06"とかを含むmrcsファイル for f in $mrcs; do echo $f done }} 連番のファイルにしたい #code(nonumber){{ #!/bin/bash mrcs=$(find /data4 -type f -name "*.mrcs") i=1 for f in $mrcs; do cmd="ln -s $f $(printf "%04d" $i).mrcs" #一旦コマンドラインに整形して、次の行で実行 $cmd i=$(expr $i + 1) done }} 既に連番を持ったファイルで偶数番号のファイルだけを拾いたい #code(nonumber){{ #!/bin/bash tif=$(find . -name "*.tif") i=1 for f in $tif; do #aaaa num=$(echo $f | cut -c6-9|bc) # ファイル名の連番部分を切り出して(cut)、数字にします(bc) if [ $(($num%2)) == 0 ]; then # 2で割った余りで偶数/奇数を見る echo $f fi done }} ***for文 一行で [#i38c4710] #code(nonumber){{ for i in `ls *.tif`; do echo $i ;done }} 一分ごとにコマンドを実行 #code(nonumber){{ for i in `ls *.tif`;do echo $i; cp $i /xxx/xxx/Micrographs/ ;sleep 60; done }} ***超簡易並列 [#k1c6d70e] 多数のディレクトリに対して処理を施したいが、どうせなら複数のジョブを流して対処したい っで作ってみた #code(nonumber,nooutline,nolink){{ #!/bin/bash cat <<'_EOF_'>run.$$.sh # 個々のディレクトリで動くスクリプト #!/bin/bash echo start:`date '+%y%m%d %H:%M:%S'` expr `cat max |bc` - 1 > max <目的の処理> expr `cat max |bc` + 1 > max echo end:`date '+%y%m%d %H:%M:%S'` _EOF_ chmod +x run.$$.sh echo 8 > max. # 同時実行数 for d in `find . -maxdepth 2 -mindepth 2 -type d`; do # ターゲットのディレクトリを取得 ./run.$$.sh $d & # 「&」でバックグラウンド処理へ回す sync # 「max」ファイルの同期に必須 if [ $(expr `cat max`) -eq 0 ]; then while : do sleep 10 echo "break:" `cat max` if [ $(expr `cat max`) -gt 0 ]; then break fi done fi done rm -f run.$$.sh max }} ***文字列操作 [#me528a5d] #code(nonumber){{ pid=12345.chaperone.jp echo ${pid%%.*} ---> 12345 echo ${pid%.*} ---> 12345.chaperone echo ${pid#*.} ---> chaperone.jp echo ${pid##*.} ---> jp #-------------------------------# dir="/var/lib/pbs" echo ${dir##*/} ---> pbs *注意 dir="/var/lib/pbs/"なら ""(なし)になる echo ${dir#*/} ---> var/torque/pbs echo ${dir%/*} ---> /var/torque *注意 dir="/var/lib/pbs/"なら "/var/torque/pbs"となる echo ${dir%%/*} ---> "" (なし) #-------------------------------# tif="Micrographs/s1_100001_movie.tif" echo ${tif/_movie.tif}.mrc --> Micrographs/s1_100001.mrc }} ***空行とコメント行(#)を取り除くには [#d431690f] #code(nonumber){{ [root@c ~]# sed '/^#/d' /etc/chrony.conf | sed '/^$/d' server ntp.nict.jp iburst driftfile /var/lib/chrony/drift makestep 1.0 3 rtcsync keyfile /etc/chrony.keys leapsectz right/UTC logdir /var/log/chrony [root@c ~]# }} ***マシン同士のバックアップ [#f6108dc4] 方法はたくさんある。 rsync, rsnapshot, lsync,, 簡単に #code(nonumber){{ #!/bin/bash # log=backup.log # d=$(date +%y%m%d_%H%M%S) # if [ -f runfile ];then echo "This backup script is already running ($d)" exit else /bin/cat <<_EOF_>runfile start: $d _EOF_ cmd="rsync -avz -delete --log-file=/var/log/rsync-`date +"%Y%m%d-%H%M"`.log \ --log-file-format=\"%o %f (%U %B) %l %b\" /home/ root@backup:/backup/home/" $cmd /bin/rm -f runfile fi }} ***容量確認 [#bb4fc947] &color(red){みかんせい}; #code(nonumber){{ d=$(/usr/bin/df -l -t xfs -h | /usr/bin/grep data| /usr/bin/awk '{print $6}'| /usr/bin/sort -n) for i in $d ;do find $i -mindepth 1 -maxdepth 1 -type d -exec du -hs {} \; don }}