初歩のシェルスクリプトで遊ぶ[ファイルのリネームツール、のようなもの?_(5)]
そのまんまで済まんっすが。仕様のメモのHTMLです。
大部分は、スクリプトを見ないと理解できないけど。
joinコマンドでリネームの重複を検査する、のが工夫、かな?
シェルスクリプトでファイルのリネームツールを作るとき、リネームの途中でファイル名が同じものが出来てしまうと困るわけっす。それをリネーム実行前に検査するのを、『burdockUI』ではどうやってるか、のメモが書いてある。
ちゃんと動くのか、いちばん大事なそこが曖昧だけども。
でも、動作速度については、かなり早いっす。10000ファイルのリネームを検査するくらいは、余裕でいけます。
『burdock』仕様_備忘録
Coreのリネーム命令関係シェル変数
引数、オプションを受け取って変数に入れるまで
- | 変数名 | 中身(の例) |
---|---|---|
コマンドの生データ | $CMD_1D[@] | sed "s/^/${var}/" |
コマンド適用対象 | $CMD_TARGET[@] | name,ext |
データベース変数モード | $CMD_VAR_MODE[@] | escape,database,shell |
コマンド実行タイプ | $CMD_ACTION[@] | loop,once |
ひとつのコマンドにつき、コマンドの適用対象、データベース変数、実行タイプ、これらがすべて同じ数だけ作られる。
変数名の変形1_コマンドの生データを加工
- --shell
-
[0]: sed "s/^/${var}/"
- --escape
[0]: sed "s/^/\${var}/"
- --database
-
[0]: sed "s/^/${DATA_BASE[var]}/"
「CMD_1D」の中身を、シェル変数の扱いを決めるモードに従って、sedで書き換え、入れ替える。
変数名の変形2_コマンド加工データの増殖
コマンドの生データ配列を「CMD_1D」と名付けたが、これはコマンドが一直線に、一列に並んでることから決めた。一列だったのが、途中で二列になって、また一列に戻ったりはしない。テキストファイルや引数に並べて入力したコマンドと、同じ数だけある。
すべての文字データに同じコマンドを順番に適用してゆく、なら1Dで十分。それが「--loop」で一括処理するときはもちろん、「--once」でも、同じコマンドを繰り返せばいいから、1Dで問題ない。よって「--shell」「--escape」なら1Dのコマンドを繰り返し使えばいい。
「--detabase」かつ「--once」のときのみ、シェル変数を毎回入れ替える必要がある。そのために、1Dのコマンドから、ファイル1つのために1つずつ、コマンドを増殖させる。ファイルが4個なら、以下のようになる。
- | --loop | --once | --loop | --once | --loop | --once |
---|---|---|---|---|---|---|
- | --escape | --escape | --shell | --shell | --database | --database |
CMD_1D | sed "s/^/\${var}/" | sed "s/^/\${var}/" | sed "s/^/${var}/" | sed "s/^/${var}/" | sed "s/^/${DATA_BASE[var]}/" | |
CMD_2D_0 | ---- | ---- | ---- | ---- | ---- | sed "s/^/${DATA_BASE[var_0]}/" |
CMD_2D_1 | ---- | ---- | ---- | ---- | ---- | sed "s/^/${DATA_BASE[var_1]}/" |
CMD_2D_2 | ---- | ---- | ---- | ---- | ---- | sed "s/^/${DATA_BASE[var_2]}/" |
CMD_2D_3 | ---- | ---- | ---- | ---- | ---- | sed "s/^/${DATA_BASE[var_3]}/" |
「${var}」の意味 | エスケープされた単なる文字 | 左同 | シェル変数そのもの | 左同 | テキスト1行目 | テキスト(N-1)行目 |
こんな感じで、コマンドが表形式に2Dに広がる。「--database,--once」になればコマンドが増殖し、その後に「--escape」に戻れば1Dのみに戻る。
1Dのみなら、一本の鎖のように、一直線になる。「--database,--once」になったときのみ、鎖から枝分かれして、暖簾みたいにぶら下がる。
エスケープがうまくいっていれば、「${var}」は、そのまま文字扱いになる。エスケープされないなら、シェル変数として展開される。該当するシェル変数がCoreのプロセスに無いなら、空っぽになる。
「--escape」「--shell」のときは、「--loop」「--once」ともに、CMD_1Dのみを使う。「--once」のときも、CMD_1Dを繰り返し使う。
「--database」かつ「--loop」のときも、今まで同様にCMD_1Dを使う。「--once」かつ「--database」のときのみ、CMD_2Dを使う。
「DATA_BASE」は、テキストファイルから読み込んだ文字データの入った、シェル連想配列。「_0,_1,_2,_3」に「1行目,2行目,3行目,4行目」の文字が入っている。
「--once」モード時は、これらをファイル名1つに1つずつ使う。
「--loop」時は、数字の付加しない1Dの「DATA_BASE[var]」を使う。この中には、テキストファイルの文字データの中から、代表して1行目、2Dの「var_0」と同じ文字が入っている。
UIの主要シェル変数
ファイルサーチ
$ ls -i -1
393525 burdockCore_man.html
393480 burdockUI_cust.html
393393 burdockUI_man.html
393474 burdock_man.css
395264 burdock_man_img00.webp
395265 burdock_man_img01.webp
- 「ls -i」が基準。左側にi-node番号、区切りは半角空白。
- i-node番号は番号の左側に空白が有ることもありえる。
- ファイルパスは、この時点でカレントディレクトリの中だけに限定する。ディレクトリの名前は処理するが、ディレクトリの中は見てはいけない。
- 複数ディレクトリに対応するのは非常にめんどくさい。めんどくさい割に、それほど必要にならない。
- 複数ディレクトリへの対応を捨てることで、区切り文字に「/」を使えるようにする。
ファイルの分類_${NOW_FILES_ATTR[@]}
- [X,0][test -h]リンクファイル(処理しない)
- [f,1][test -f]通常のファイル
- [d,-1][test -d]通常のディレクトリ
- [X,0][else]それ以外のすべて(処理しない)
処理対象の切り替えフラグ ${ACTION_TARGET}
ユーザ設定ファイル単位ロック_${NOW_FILES_LOCK[@]}
処理するファイルと処理しないファイルの総合判定
[ファイルの分類]x[処理対象フラグ]+[ユーザ設定ファイルロック]=[判定値]
[判定値]が「3」のときのみtrueになる。
ファイルの分類 | 処理対象 | ユーザ設定ファイルロック | 判定値,真偽値 |
file(1) | file(1) | free(2) | true(3) |
file(1) | dir(-1) | free(2) | false(1) |
dir(-1) | file(1) | free(2) | false(1) |
dir(-1) | dir(-1) | free(2) | true(3) |
X(0) | file(1),dir(-1) | free(2) | false(2) |
X(0) | file(1),dir(-1) | lock(-2) | false(-2) |
file(1) | file(1) | lock(-2) | false(-1) |
dir(-1) | dir(-1) | lock(-2) | false(-1) |
file(1) | dir(-1) | lock(-2) | false(-3) |
dir(-1) | file(1) | lock(-2) | false(-3) |
- 処理対象の切り替えは「$*1」で行う。
- 終盤まで変数に文字列を入れて処理していたが、caseの文字並べで判定するしかないし、見た目も悪い。
- この算数方式だと、「5」なんかが紛れ込んで、誤判定しそうではある。
- 文字の仕様では、とにかくトグルスイッチが格好悪い。
- 判定結果も数字にできるが、とりあえずtrueとfalseで。どちらも展開した後にtrueコマンド、falseコマンドとして使える。が、今のところは使っていない。
シェル配列変数の添字
START_FILES 2[216 218] 起動時のファイル情報 ファイル名 i-node
NOW_FILES 2[216 218] 現在のファイル情報 ファイル名 i-node
NOW_FILES_ATTR 2[216 218] 現在のファイル情報 ファイルかディレクトリか
MOD_FILES 2[216 218] リネーム予想ファイル名 MOD_FILES
NOW_FILES_LOCK 2[216 218] ユーザ指定リネーム対象選択
NOW_FILES_BOOL 2[216 218] リネーム適用対象判定結果
INODE_ORDER 2[0 1] i-node番号が処理順序に格納される
- ファイルの処理順序は、端末に表示する順序と同じにする。これは原則で、例外はよっぽどでないと作らない。見た目と処理順を揃える。たとえリネーム時の重複回避目的でも順番は守る。むしろリネームを中断する。
- ファイルの処理順序は、i-node番号で保持する。「$INODE_ORDER[@]」の格納順が決めている。
- これらの配列は連想配列ではないが、配列の添字をi-node番号にする。こんなことして桁数が間に合うかは分からんが、もしエラーになるようなら、連想配列に切り替える。
UI_ファイル名の重複検査
方針
- リネーム作業はCoreの--actionで実行する。UIに(Coreの機能を代替する)リネーム機能を実装してはいけない。
- Coreは、処理順序を考えない。入ってきた順番に出力するのみ。UIは、結果と過程を予想する。リネームが正常終了する見込みなら、実行する。途中でエラーが起きると予想されるなら、最初から実行できないようにする。
- ファイル操作は最小限、つまりCoreでのmvコマンドのみ。一時ディレクトリを作って移動しながらリネーム、は禁止。
廃棄案A_実際に試してみる-本物で
一時ディレクトリに、作業ディレクトリ内のファイルと同名のファイル群を、0バイトで作成。試しにリネームしてみる。
原則に反しているので廃案。速度は意外と速かった。下手にシェル変数上で検査するより速い。でも負担膨大。
動作検証用ならいいだろう。
廃棄案B_実際に試してみる-変数の中で
配列内でファイル名のリネームを模擬して、mvコマンドの実行一回ごとに重複検査する。
コマンドでの重複検査は、sort->uniqで行った。だが、これをリネーム回数だけ繰り返すと、それなりに時間がかかった。廃棄案Aより遅い。
とはいえ、300ファイルくらいなら、実用範囲内ではあったけれど。別プロセスを呼び出さずに処理できるなら、速くできるかもしれん。見落としが無くて安心だし……。
現在使用中のjoinコマンドの方法
速いんだが、joinが安定動作するか、保証がない。理屈も思いつきで、当てにならない。
join実行前の検査
- 使えないファイル名を弾いておく。具体的には「ファイル名が空っぽ」か「ユーザ設定の使用禁止文字を使ってる」ときは使えない名前と判定する。使えない名前は、ユーザに修正要求する。
- リネーム後のファイル名「$MOD_FILES[@]」内のみで、重複するファイル名を探索しておく。もし重複するならば、同じディレクトリに同じファイル名が複数作られてしまうので、順番に関係なくエラー。ユーザに修正を求める。
- 補足:「$MOD_FILES[@]」の重複は、後のjoin検査では検出できないので、ここで実行しておく必要がある。
- 以上をクリアした時点で、ユーザが「リネームしろ」と命令するのは、正当な要求だと見なす。
以降はjoinで検査する。
join検査の基本アイデア
mvコマンドを見ると、「リネーム前のファイル名」は、「mvコマンドを実行すると消滅する名前」だともいえる。同様に「リネーム後のファイル名」は「mvコマンドを実行すると発生する名前」だ。
「消える名前」「発生する名前」
mv [リネーム前] [リネーム後]
↑ ↑
消える名前 発生する名前
リネーム前の「$NOW_FILES[@]」は、消える名前の集合。
リネーム後の「$MOD_FILES[@]」は、発生する名前の集合。
ファイル名の重複とは、「消える名前の集合」と「発生する名前の集合」に同じ名前があって、なおかつ、同じ名前が二つ同時に存在してしまう、ということ。
よって、ある名前が、「消えてから発生する」なら、重複しない。
「発生してから消える」ときは、重複してしまう。
「発生と同時に消える」なら、それは「mv file.txt file.txt」のようなコマンドを実行するのを意味してる。
重複する例
mv実行順番(INODE_ORDER[@]配列番号) | $NOW_FILES[@] | mv0実行時 | $MOD_FILES[@] |
---|---|---|---|
0 | file01.txt | file02.txt | file02.txt |
1 | file02.txt | file02.txt | file03.txt |
2 | file03.txt | file03.txt | file04.txt |
mvコマンドは配列の順番に実行するのだから、配列番号がそのまま「消える番号」「発生する番号」になる。
この例では、リネーム後のファイル名に重複はないし、ファイル名自体にも問題はない。しかし配列番号0、mvコマンドの初回で、重複が起きている。
「file02.txt」に注目すると、「1回目のmvコマンドで消滅し、0回目のmvコマンドで発生する」ことがわかる。
重複しない例
mv実行順番(INODE_ORDER[@]配列番号) | $NOW_FILES[@] | mv0実行時 | mv1実行時 | $MOD_FILES[@] |
---|---|---|---|---|
0 | file02.txt | file01.txt | file01.txt | file01.txt |
1 | file03.txt | file03.txt | file02.txt | file02.txt |
2 | file04.txt | file04.txt | file04.txt | file03.txt |
「0番で消えて1番で発生する」なら、重複は起こっていない。
joinで検査できないこと、あらかじめ検査しておくこと
- ファイル名に使ってはいけない文字が入ってないか、ファイル名が空っぽの0文字になっていないか。
ファイル名に使えない文字や空のファイル名が入っていても、join検査から見ると、単なる文字列の1つにしかならない。
- リネーム完了後のディレクトリ内で、同じファイル名が重複していないか。
join検査は、mvコマンド1回についてしか調べられない。同じ名前が何度も出てきても、mv実行順番の数字だけを比較して判定する。
join検査例
ファイル名に「何番目に消えるのか」と「何番目に発生するのか」の数字を付加した文字列を作成する。
下記の例では、通常は「06.jpg,07.jpg…」と並ぶが、ソートで逆順にしてある。「10.jpg,09.jpg,08.jpg…」とmv処理している。
- 「$NOW_FILES[@]」「$MOD_FILES[@]」の行頭に、「行番号/」を付加。その後、ファイル名でソート。
- joinコマンドで結合。結合フィールドはファイル名。区切りは「/」。同じファイル名があれば、出力される。
- 「/N/M」の数値を比較する。
- 重複を検知した例
-
-
-
- ${BB} Before------------------
-
-
4/06.txt
3/07.txt
2/08.txt
1/09.txt
0/10.txt-
-
-
- ${AA} After-------------------
-
-
4/05.txt
3/06.txt
2/07.txt
1/08.txt
0/09.txt-
-
-
- ${CC} join -------------------
-
-
06.txt/4/3
07.txt/3/2
08.txt/2/1
09.txt/1/0
リネーム前後で同一のファイル名があります。mvコマンドの順序を検査します。
06.txt:ERR_ファイル名重複
07.txt:ERR_ファイル名重複
08.txt:ERR_ファイル名重複
09.txt:ERR_ファイル名重複
ファイル名に重複があります。 -
重複検査に合格した例
-
-
-
- ${BB} Before------------------
-
-
4/06.txt
3/07.txt
2/08.txt
1/09.txt
0/10.txt-
-
-
- ${AA} After-------------------
-
-
4/07.txt
3/08.txt
2/09.txt
1/10.txt
0/11.txt-
-
-
- ${CC} join -------------------
-
-
07.txt/3/4
08.txt/2/3
09.txt/1/2
10.txt/0/1
リネーム前後で同一のファイル名があります。mvコマンドの順序を検査します。
07.txt:正常リネーム
08.txt:正常リネーム
09.txt:正常リネーム
10.txt:正常リネーム
重複検査に合格しました。-
- 「Before」については、「[ファイル名]は、[数字N]回数目のmvコマンドで、消滅する」を意味している。
- 「After」については、「[ファイル名]は、[数字M]回数目のmvコマンドで、出現する」を意味している。
- もしjoin結果が空ならば、リネーム前後に重複ファイルは無い。.....OK
- 「ファイル名が消えてから出現する」......「N < M」ならリネーム..OK
- 「ファイル名が消えると同時に出現する」..「N = M」なら無変更....OK
- 「ファイル名が出現してから消える」......「N > M」なら重複......NG
joinコマンドのややこしさ
ファイル名でjoinすればよいんだが、joinコマンドはソートしてからでないとエラーを返してくる。これがよくわからない。
おそらくjoinするフィールドでソートすればいいんだろうが、ソートはどの言語でしたらいいんだろうか。それぞれ同じ言語でソートしていればいいんだろうか。今は「LC_ALL=C」としてある。駄目なら日本語設定に戻すか、英語設定。他に選択肢はないだろう。
問題は、区切り文字。今は「行番号/」でソートしているが、これは当初、行末に「/行番号」でソートして、jionが時々エラーを返してきたから。
区切り文字に水平タブか半角空白を使えばエラーにならなかったんだが、『burdock』では「/」を使うしかない。どうやらソートしたフィールドの後に、「/」のような、文字コードで半角空白より大きい数字の文字を使うと、ソートエラーの扱いになるようだ。
しょうがないので、ソートした後には改行が来るようにして、数字を先に置いて「/」を区切り文字とした。『burdockUI』は複数ディレクトリに対応しないでファイル名のみで処理するから、ファイル名に「/」が入ることはない。
Core,UI_ファイルの拡張子,プリフィックス
- 〜.sh
- 実行権限が必要なシェルスクリプトファイル。全てのスクリプトはbashで動作しなければならない。他のシェルでも動作するなら、なお望ましいが、必須ではない。
- 〜.func
- 「.」コマンドで読み込むファイル。中身はシェルスクリプト。実行権限は不要。スクリプトの起動処理で一回読み込んだら、二度と読み込まずに済むようにすること。
- 〜.txt
- テキストファイルだが、中身は「〜.func」と同様でも構わない。ユーザ寄りのテキストファイルだと感づいてもらうために「.txt」にする。中身は人間が読むためのテキストファイルか、読み込み専用のシェル変数設定ファイルなど。ファイルを入れ替えれば個人設定を切り替えられるようにする。
- _〜
- Core用の追加スクリプトファイル。許可リストに「_」が登録してある。拡張子は無いが実行権限は必要。
- XXXX.N.sh
- ファイル情報作成用スクリプトファイルの名前。2重拡張子にすると、「N」の部分が削られて、シェル変数の名前に使われる。1つのコマンドを2つ以上のスクリプトで使う場合は、2重拡張子にして区別する。ImageMagickのように、得られる情報が多いコマンドの場合は、適度に分けたほうがよい。
UI_シェル関数の大分類
- APP_ID_100()
- 選択メニューから呼び出すシェル関数のうち、UIのシステム用。スコープは色々。
- APP_ID_900()
- 選択メニューから呼び出すシェル関数のうち、システムのデバッグ用のシェル関数。スコープは色々。
- APP_ID_200()
- 選択メニューから呼び出すシェル関数のうち、アプリケーション的な、無くてもUIの基本動作に支障のないシェル関数。Coreの追加スクリプトをリネーム用コマンドとして追加するためのもの。
- 〜Sh()
- データの入力に引数等、出力に標準出力等を使う。独立したスクリプトファイルに切り離せるもの。少ない。
- 〜Sub()
- サブシェルの「()」で動作する。メインプロセスのシェル変数を引き継ぐ必要はあるが、メインプロセスのシェル変数を変更しない。
- 〜Func()
- メインプロセスのシェル変数を変更する。メインプロセス上で動作させる必要があるもの。サブシェルにしてはならない。
UI_ファイルビューア端末出力規格
- UIのプロセスが保持している、ファイル情報関連のシェル配列変数を、端末に展開表示する。UIの動作状態監視を兼ねている、ということ。
- UIは、標準出力から配列情報を出力する。外部スクリプトが、これを受け取って整形する。
標準出力を区切って出力する+最大表示数を制限する
レイアウトにcolumnコマンドを使っている関係上、すべてのデータ送信と処理が終わらないと、何も表示してくれない。ファイル数が膨大になると、無反応状態が長時間続いてしまう。
対策として、まず、最大表示数を制限する。
次に、ファイルを、たとえば1000ファイル出力するごとに、columnコマンドを含めた外部スクリプトを起動・終了させる。
while 「最大表示数を制限する条件」 ; do
for N in `seq 0 999` ; do
echo 'XXXX/XXXX/XXXX/XXXX/XXXX/XXXX/'
done | 「columnを含めた外部コマンド」
done
外側のwhileループから見ると、すべてのデータは途切れずに標準出力される。内側のforループから見ると、1000ファイルごとにパイプの先のコマンドにデータを出力する。
bashが外部コマンドを起動せず、配列を展開してechoするだけでも、無視できない時間がかかる。解決は困難なので、UIのプロセスには配列の展開と標準出力のみを実行させる。
表示の整形は、外部スクリプトが担当する。
ファイル情報送信仕様
- 詳細出力
- echo "${NOW_FILES_BOOL[${IND}]}/${NOW_FILES[${IND}]}/${MOD_FILES[${IND}]}/${NN}/${IND}/${NOW_FILES_ATTR[${IND}]}/${NOW_FILES_LOCK[${IND}]}"
- 簡易出力
- echo "${NOW_FILES_BOOL[${IND}]}/${NOW_FILES[${IND}]}/${MOD_FILES[${IND}]}"
- 解説
1(詳・簡) 2(詳・簡) 3(詳・簡) 4(詳) 5(詳) 6(詳) 7(詳) filesBool nowFiles modFiles 配列番号 inode f-d-X free-lock true,false ファイル名(サーチ結果) ファイル名(リネーム予想) 数字(0から連番) 数字(不定) 1,-1,0 2,-2
UI_アプリケーション設定とカスタマイズ
規格に沿った名前のシェル関数を作る
「100」〜「999」
↓
APP_ID_100(){
clear
}
↑
「APP_ID_」すべて共通
- 「100」〜「199」UI制御用_menuSys0.finc
- 「200」〜「299」リネーム機能用_menuApp0.func
- 「900」〜「901」debug
「000」〜「099」は使わない。この数字をシェル配列変数の添字にするから。頭に「0」のついた数字は、8進数扱いになって、使いにくい。
何ページの何番に何のシェル関数を置くのか_${APPLICATION_CALL[ページ番号]}
APPLICATION_CALL_01[0]='201' # 名前クリア_echo
APPLICATION_CALL_02[0]='202' # _suffix
APPLICATION_CALL_03[0]='203' # 簡易連番
「ID_APP_」を除いた、3桁の数字のみを代入する。
どのように実行されるのか
case
↓「1」
____________
( "${KEY_SETTING_01}" ) APP_ID_${APPLICATION_CALL_01[${menuPage}]} ;;
( "${KEY_SETTING_02}" ) APP_ID_${APPLICATION_CALL_02[${menuPage}]} ;;
( "${KEY_SETTING_03}" ) APP_ID_${APPLICATION_CALL_03[${menuPage}]} ;;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
↑「201」,「202」,「203」
esac
ページ番号が数字で配列に入り、「${APPLICATION_CALL_01[0]}」が展開されて「201」の3桁の数字に展開され、「APP_ID_」と繋がって、シェル関数「APP_ID_201」が実行される。
コマンドリスト表示スクリプトとのシェル変数ファイルの共通化
- 「${APPLICATION_CALL[]}」を書き換えると、コマンドリスト表示スクリプトでも、表示が自動で切り替わるようにしたい。
- つまり、シェル変数の設定ファイルを、UIのメインプロセスと共用したい。
- 設定ファイルは共用したいが、不要なシェル変数の読み込みは避けたい。
- 設定ファイルは、ファイルを入れ替えれば簡単なカスタマイズができるようにしたい。
シェル関数にラベルをつける
LBL_ID[201]='名前クリア'
LBL_ID[202]='_suffix'
LBL_ID[203]='連番(簡易)'
シェル配列変数を作成して、ラベルの文字を決める。添字の数字を、「APP_ID_XXX」の末尾3桁の数字にする。
設定からラベルの文字列を取得する(evalと連想配列無しで)
↓「${LBL_ID_[201]}」
_____________________________________
LBL_01="${LBL_ID[${APPLICATION_CALL_01[${PN}]}]}"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
↑「201」などの3桁の数字LBL_02="${LBL_ID[${APPLICATION_CALL_02[${PN}]}]}"
LBL_03="${LBL_ID[${APPLICATION_CALL_03[${PN}]}]}"
- シェル関数名は、数字のみでは作れない。頭にアルファベットなどが必要。
- 簡単にラベルを設定するなら、連想配列で「${LBL_[APP_ID_201]}」とすればよいが、これは避けたい。
- 「foo${var}='XXXX'」の書き方では、evalが必要になる。
- シェル関数(とコマンド)なら、「func${var}」でも、evalせずにそのまま実行できる。
- 配列変数に数字のみ入れる仕様でまとめることができれば、連想配列を使わずにラベル文字列を取り出せる。さらに、変数展開して頭に「APP_ID_」を並べれば、これもevalせずそのまま実行できる。
スクリプトを識別するシェル変数を作って読み分ける
- 同種の設定は同じファイルにまとめたい。
- ところが、「.」で単純に読み込むと、使わないシェル変数まで読み込んでしまう。
- よって、シェルスクリプトのプロセスに「BURDOCK_PROCESS=''」を設定して、caseで読み分ける。
UI_主ループ中のシェル変数の状態と更新タイミング
- ◎
- 値を作成・更新
- ↓
- 値を維持する
- ----
- 未作成
- ='' =()
- 変数や配列の中身を空にする
- ='???'
- 選択された機能によっては変更が有る
- return2↑
- resetFlag='true'と等価。終了コード2で自動リセットする。
- | resetFlag | START_FILES[@] | NOW_FILES[@] | NOW_FILES_ATTR[@] | INODE_ORDER[@] | NOW_FILES_LOCK[@] | MOD_FILES[@] | NOW_FILES_BOOL[@] | COMMAND_LIST[@] | CMD_LIST_DOG[@] | CMD_LIST_CURRENT | CMD_MEM_WRITE_FLAG |
---|---|---|---|---|---|---|---|---|---|---|---|---|
メインループ開始前 | ='true' | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ='' |
ループ開始 | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ |
resetFlag判定 | ='false' | true)◎ false)↓ |
true)◎ false)↓ |
true)◎ false)↓ |
true)◎ false)↓ |
true)◎ false)↓ |
true)=() false)↓ |
true)◎ false)↓ |
↓ | ↓ | ↓ | ↓ |
コマンドファイル読み込み | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | *)◎ | ↓ | *)◎ | *)='false' |
read待ち | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ |
機能実行(ファイルスキャン・ファイル数変動) | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ |
機能実行(ファイルスキャン・i-node変動) | return2↑ | return2↑ | ◎return2↑ | ◎return2↑ | ◎return2↑ | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ |
機能実行(ファイルスキャン・通常) | ↓ | ↓ | ◎ | ◎ | ◎ | ↓ | ◎ | ◎ | ↓ | ↓ | ↓ | ↓ |
機能実行(リネーム実行) | ↓ | ↓ | ◎ | ◎ | ◎ | ↓ | ◎→=() | ◎ | =() | ◎ | ↓ | ='true' |
機能実行(その他) | ||||||||||||
ループ最終処理 | ||||||||||||
- | ACTION_TARGET | modFilesReliabilityFlag | inodeOrderSyncFlag | fileSearchNo | fileViewerNo | menuPage |
---|---|---|---|---|---|---|
メインループ開始前 | ='' | ='' | ='' | ='' | ='' | ='' |
ループ開始 | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ |
resetFlag判定 | true)='1' false)↓ |
true)='false' false)↓ |
true)='true' false)↓ |
true)='0' false)↓ |
true)='0' false)↓ |
true)='0' false)↓ |
コマンドファイル読み込み | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ |
read待ち | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ |
機能実行(ファイルスキャン・ファイル数変動) | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ |
機能実行(ファイルスキャン・i-node変動) | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ | return2↑ |
機能実行(ファイルスキャン・通常) | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ |
機能実行(リネーム実行) | ↓ | ↓ | ↓ | ↓ | ↓ | ↓ |
機能実行(その他) | ユーザ指定切り替え | ↓ | ユーザ指定切り替え | ユーザ指定切り替え | ユーザ指定切り替え | ユーザ指定切り替え |
ループ最終処理 | コマンド追加時に='false' | |||||
UI_mvコマンド実行前の作業流れ
- リネーム予想ファイル名「MOD_FILES[@]」が古いならば、作り直す。
- 「MOD_FILES[@]」に、空のファイル名が無いかを点検する。
- 「MOD_FILES[@]」に、ユーザ指定禁止文字が使われていないかを点検する。
- 重複検査1_「MOD_FILES[@]」内で重複がないかを点検する。
- 重複検査2_「NOW_FILES[@]」「MOD_FILES[@]」をまとめて点検して、すべてのファイル名が異なるならば、重複する可能性は無いと見なして、重複検査3を省略する。
- 重複検査3_リネームの作業途中で重複が発生しないかを点検する。
- 「MOD_FILES[@]」に、WS-Windowsで使えない文字が入っているかを点検し、もし入っているならば注意を促す。リネームは可能。
不正なファイル名を検査する機能
burdockCore.shを「--action」で実行したとき、最初から最後までエラーが出ないでスムーズに実行できること、を主目的とする。
エラー発生が予想できるなら、はじめから実行できないようにする。リネーム作業を中断させる。
[禁止]ファイル名が空っぽ(何も無い)になっていないか?
- 「空っぽ」というのは、名前部分も拡張子部分も含めて何も無い、ということ。半角空白が一つだけでもあれば、「空っぽ」ではない。
[禁止]ユーザが使用可能文字を制限しているならば、使用不可能な文字が入っているか?
「ARROW_CHAR.txt」が空、または改行文字だけならば、ユーザが禁止する文字は無いと見なす。
もし改行文字以外の文字が入っていれば、ユーザは「これらの文字だけの使用を許可する」と見なす。
[禁止]希望するリネーム後のファイル名が、ディレクトリの中で重複していないか?
「リネーム後」のファイル名の重複なので、ユーザの責任。burdock側で回避できない。
[禁止]リネーム後のファイル名が重複していないときでも、リネーム途中でファイル名の重複が起きたりしないか?
「リネーム途中」のファイル名の重複なので、burdock側の仕様が関わる問題。burdock側で回避は可能だが、問題が見つかったら単純にリネーム禁止とする。
burdockは「見た目の順番が処理の順番」「リネームはCoreの機能一種類のみで実行する」という方針だ。リネーム順序を変更して重複を回避する処理を入れたり、一時ディレクトリを作成して移動しながらリネームはしない。
[警告]MS-Windowsで一般に使えない文字が入ってはいないか?
一般にWindowsで使おうとしても怒られる文字に加えて、制御文字を探す。見つかったら注意表示する。ユーザが許可するなら、そのままリネームを実行しても構わない。
課題とか見送ったこととか不安材料とか
- i-node番号を使う仕様自体、再検討すべきかもしれんが。もしファイル名だけで管理するなら、元に戻すために名前変更履歴を残す必要がある。だが、これだとファイラーで横から割り込んでリネームすると混乱してしまう。「ちょっとこれだけ手直ししたい」ということはよくあるし。
メッセージの切り替え機能を実装するか、実装しないとしても実装可能なまで整理ができないか。言語ファイルの切り替え的な。スクリプトの中に日本語を埋め込んでいて、切り離せないのは気持ち悪い。個人設定ファイルと、スクリプト本体の完全分離。スクリプトファイルを共有ディレクトリに置いて、個人設定はホームディレクトリに置けないか。できる気はするが、試作試行必須。呼び出したアプリケーションの操作系をカスタマイズできないか。いろいろな問題の解決として、操作系の規格化。「はい/いいえ」「複数選択」「表題」「説明文」くらいに規格化できないものか。- Coreくらいはbash専用でなく、他のシェルでも動くものを書くのはどうか。具体的にはdash,busybox共用。
- awkのgensub関数を使ってしまってるところ、なんとかならんものか。awkを使わないで済ませるなり、使うなら使うで、互換モードに限定したうえで、他の機能も有効利用するなり。「sedが書けないから検索してとってつけました感」が格好悪すぎる。むしろ、こんなことしなくていいように、仕様から変える?
- 用途の大部分は、database変数モードを無くし、--loop動作のみにした簡易型で済むんじゃなかろうか。外部スクリプトは必要だが。
- 「IFS='あ'」とかやっちゃってるところ、大丈夫か? やるなら追加の単体スクリプトに限定しておこう。
- 日本語の文字数を数えるときには、cutとかは使えなかった。sedはマルチバイト文字でもいける、ようなことが説明書に書いてあった気がする。bashの変数展開で、無理矢理に「日本語の区切り文字と改行を入れ替え」なんてしてしまったが、大丈夫な保証が見つからん。
- ファイル表示やコマンド表示スクリプトで、ループ処理からcolumnをパイプで繋ぐと、シェル変数のプロセスが切れる。見落としやすいので注意。
*1: ${var} * -1