シェルスクリプトによるファイルの間引き part2

さらに昨日の続き。
環境のまとめ。

〜〜2014/8/28 追記ここから〜〜
下に書いてたゼロパディング、printf コマンドを使えばもっと効率よくできた。
# printf "%05d" $ii
環境にコマンドがあれば、5桁ならこんなんでヨサゲ。
〜〜2014/8/28 追記ここまで〜〜

~~ 2019/5/5 追記ここから ~~
連番を作る方法も簡単になっているので、追記

0 から 100 までの連番なら、1 ラインでいける。
printf "work%03d.txt\n" {0..100}

もしくは

echo {000..100}
~~ 2019/5/5 追記ここまで ~~

Windows上の作業フォルダ d:\gifwork
玄箱上の作業ディレクト /mnt/share/gifwork
玄箱上のアカウント neko
やりたいこと 規則的に数値が割り振られて並ぶファイルを、2個消して1個残す


Windows上のテキストエディタ(僕の場合は EmEditor)でシェルスクリプトを作成する。
ファイル名は、適当に wk.sh とした。


仕様としては…
・ファイル名と連番と拡張子を、それぞれの変数に入力して組み合わせて表示させる。


とりあえず、これ(ファイル名のソート)ができないと安心してプログラムを実行できない。

#!/bin/sh
# 2007.03.04 初版作成(黒猫666) 
# 目的 とりあえずファイル名を連番で表示させる。

# ファイル名(File Name)
WkName="work"

# 拡張子名(Extension Name)
WkExt=".bmp"

# ファイル数のループカウンタ変数
ii=1

# (終了条件 ファイル名が無い場合)
while [ -f ${WkName}${ii}${WkExt} ]; do
	echo "${WkName}${ii}${WkExt}"
	ii=`expr $ii + 1`
done

こんなもんかな?
できあがったものを実行してみる。
wk.sh


neko@KURO-BOX:/mnt/share/gifwork$ sh wk.sh
work1.bmp
work2.bmp
work3.bmp
work4.bmp
work5.bmp
work6.bmp
work7.bmp
work8.bmp
work9.bmp
work10.bmp
work11.bmp
work12.bmp
work13.bmp
work14.bmp
work15.bmp
work16.bmp
work17.bmp
work18.bmp
work19.bmp
work20.bmp


うん、キレイに並んだ。
…と思ったけど、ファイル名って、0がいくつも並んで桁が合ってるんだよね。
このままでは使い物にならない。
桁あわせって、どうすればいいんだろ?
てゆーか、それは最初に仕様へ盛り込んでおくべきだったな。


仕様上、処理がちょっと大変になってきたw
でも、何回も使いまわすものだし、今作っておけば応用も利きそうなので頑張ってみる。
ここで別途「特定桁数の連番を表示させる機能」を実現するためのテストシェルスクリプトを作ってみよう。
…本来的に、求めるべきではない機能だと思うけど(TT)


ソースを引用すると、かなり長くなりそうなのでリンクのみ…
digit.sh
これの実行結果は、以下の通り

neko@KURO-BOX:/mnt/share/gifwork$ sh digit.sh
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010


ここでは10個までしか引用しないけど、実際には105個まで表示された。


では、実際のファイル数をチェックして、前後にファイル名と拡張子をつけてみた場合の wk02.sh の実行結果。

neko@KURO-BOX:/mnt/share/gifwork$ sh wk02.sh
work00001.bmp
work00002.bmp
work00003.bmp
work00004.bmp
work00005.bmp
work00006.bmp
work00007.bmp
work00008.bmp
work00009.bmp
work00010.bmp
work00011.bmp
work00012.bmp
work00013.bmp
work00014.bmp
work00015.bmp
work00016.bmp
work00017.bmp
work00018.bmp
work00019.bmp
work00020.bmp
work00021.bmp


よしよし…カタチになってきてるゾw
では、特定のファイルだけ削除していくように追記した wk03.sh を実行。
ただし、いきなり削除すると変な挙動が怖いので、実行されるべきコマンドを echo で表示するだけにしておく。

neko@KURO-BOX:/mnt/share/gifwork$ sh wk03.sh
> work00001.bmp
rm -f work00002.bmp
rm -f work00003.bmp
> work00004.bmp
rm -f work00005.bmp
rm -f work00006.bmp
> work00007.bmp
rm -f work00008.bmp
rm -f work00009.bmp
> work00010.bmp
rm -f work00011.bmp
rm -f work00012.bmp
> work00013.bmp
rm -f work00014.bmp
rm -f work00015.bmp
> work00016.bmp
rm -f work00017.bmp
rm -f work00018.bmp
> work00019.bmp
rm -f work00020.bmp
rm -f work00021.bmp


完璧!
ここまで頑張った甲斐があったというモノ。
実行されるべきコマンドこそ echo で潰しているけど、それさえ削除すればきちんと動作するバージョン wk04.sh を実行。

neko@KURO-BOX:/mnt/share/gifwork$ sh wk04.sh
rm -f work00002.bmp
rm -f work00003.bmp
rm -f work00004.bmp
rm -f work00005.bmp
rm -f work00007.bmp
rm -f work00008.bmp
rm -f work00009.bmp
rm -f work00010.bmp
rm -f work00012.bmp
rm -f work00013.bmp
rm -f work00014.bmp
rm -f work00015.bmp
rm -f work00017.bmp
rm -f work00018.bmp
rm -f work00019.bmp
rm -f work00020.bmp


大丈夫だね…ここまでやって一安心。
wk04.sh のソースは引用。

#!/bin/sh
WkName="work"
WkExt=".bmp"
RmStep="5"
ExNum=1
WkDigit="5"
ii=1
WkStep=1
bmpNum=`ls *.bmp | wc -l`
until [ "$ii" -gt "$bmpNum" ]; do
	iiNum="`echo ${#ii}`"
	if [ "$iiNum" -le "$WkDigit" ]; then
		wkii=`expr $WkDigit - $iiNum`
		wkzr=""
		count=0
		while [ "$count" -lt "$wkii" ]; do
			wkzr="`echo ${wkzr}0`"
			count=`expr $count + 1`
		done
	fi
	if [ "$WkStep" -le "$RmStep" ]; then
		if [ "$ExNum" -lt "$WkStep" ]; then
			echo "rm -f ${WkName}${wkzr}${ii}${WkExt}"
		fi
			WkStep="`expr $WkStep + 1`"
	else
		WkStep=2
	fi
	ii=`expr $ii + 1`
done

シェルスクリプト 23行目の
echo "rm -f ${WkName}${wkzr}${ii}${WkExt}"

rm -f ${WkName}${wkzr}${ii}${WkExt}
に書き換えてあげれば、実際に削除するヨ。


あと…細かいチューニング方法を。


WkName="work" は、ファイル名
WkExt=".bmp" は、拡張子
RmStep="5" のところはステップ数で、3に書き換えてもらえれば対象を3つ分ずつ
ExNum=1 は、1番目のみ残すという意味
WkDigit="5" は、5桁の数字(00001とか)を意味しているので、4にすれば4桁(0001)になる。



今日は長かったなぁw
って、これで済まそうと思ったけど、やっぱりソースコードが分かりにくいので wk03.sh を当初の目的にカスタムしたソースを貼り付け
どういう理屈で動いてるかまでわかったら、システムエンジニアになれるw
id:STARLESS氏に捧ぐ下記スクリプトは、テキストファイルにコピペして、画像ファイルのあるフォルダに適当なファイル名(アルファベット)で保存して、玄箱上で実行してあげれば簡単にファイルを間引けます。
※ 実際にファイルが削除されることに注意してくださいな。

#!/bin/sh

# version 情報
# 2007.03.03 初版作成(黒猫666) 
# 2007.03.04 目的は果たせそうなスクリプトに成長(黒猫666) 
# 目的 マジで連番ファイルから規則的にファイルを抽出できるフリーソフト
#      0001 ,0004 ,0007〜みたいな感じで2枚飛ばしで連番BMPファイルを抽出すればいい

# スクリプト名 filedelet.sh

# ファイル名(File Name)
WkName=""

# 拡張子名(Extension Name)
WkExt=".bmp"

# ステップ(削除ファイルをいくつ単位にするか2枚飛ばしの場合は、3を設定)
RmStep="3"

# 残す数(RmStepが3でExNumが1 の場合、一つ目を残して2個目、3個目を削除)
ExNum=1

# 桁数の指定(数値が4桁なら、4)
WkDigit="4"

#### 以下、修正の必要なし。
# ループカウンタ変数
ii=1
WkStep=1

bmpNum=`ls *.bmp | wc -l`

# (終了条件 bmpファイル数分回まわったら)
until [ "$ii" -gt "$bmpNum" ]; do
	# 桁数のチェック
	iiNum="`echo ${#ii}`"
	# 桁数が指定数以下であれば…
	if [ "$iiNum" -le "$WkDigit" ]; then
		# 指定数から桁数を引いた数ぶん、0を追記
		wkii=`expr $WkDigit - $iiNum`
		wkzr=""
		count=0
		# 指定数分、0をつくる
		while [ "$count" -lt "$wkii" ]; do
			wkzr="`echo ${wkzr}0`"
			count=`expr $count + 1`
		done
	fi
	#echo "${WkName}${wkzr}${ii}${WkExt}"
	
	# では、実際に削除作業を…
	# WkStepが指定数(RmStep)以下の場合に
	if [ "$WkStep" -le "$RmStep" ]; then
		# 指定数が、残す数以下であれば、残す。
		if [ "$ExNum" -lt "$WkStep" ]; then
			#echo "$WkStep, $RmStep"
			echo "rm -f ${WkName}${wkzr}${ii}${WkExt}"
		else
			echo "> ${WkName}${wkzr}${ii}${WkExt}"
			${WkName}${wkzr}${ii}${WkExt}
		fi
			WkStep="`expr $WkStep + 1`"
	else
		WkStep=2
		echo "> ${WkName}${wkzr}${ii}${WkExt}"
	fi
	
	# ループ処理
	ii=`expr $ii + 1`
done

# 終了処理
exit 0