ファイル名の整頓
意外と面倒だけど大事なこの項目。
最初に設定すると、あとの手数を減らせるので、今のうちに考えておきます。
必要なもの
患者番号 検査時期 シーケンス ぐらいですかね。
ここはいよいよシェルスクリプトの出番でしょうか。
私の環境はmac なので、zshでいきます。
例によってチャッピーと相談だよ!

出力ファイルの命名規則を以下に設定
<ID>_<検査時期>_<シーケンス>.nii.gz
検査時期は被験者によって違うのと、タイミングをグループ別にするので二段階にして、まずは検査時期→日付8桁の作業としました。
というわけでできたスクリプトは
(T1 / T1C / T2、.nii/.nii.gz/.json を揃えてrename)
#!/usr/bin/env zsh
set -euo pipefail
setopt null_glob
DRYRUN=1
if [[ "${1:-}" == "--run" ]]; then
DRYRUN=0
fi
strip_nii_ext() {
local f="$1"
if [[ "$f" == *.nii.gz ]]; then
print -r -- "${f%.nii.gz}"
else
print -r -- "${f%.nii}"
fi
}
get_pid() { [[ "$1" == "_" ]] && print -r -- "${1%%_*}" || print -r -- "$1"; }
get_ymd() {
local base="$1"
if [[ "$base" =~ ([0-9]{14}) ]]; then
local ts="${match[1]}"
print -r -- "${ts[1,8]}"
else
print -u2 "SKIP (no 14-digit timestamp): $base"
return 1
fi
}
infer_mod_3() {
local s="${1:l}"
if [[ "$s" == "+c" || "$s" == "+ce" || "$s" == "sag+c" || "$s" == "ce" || "$s" == "ce_t1" || "$s" == "t1c" ]]; then
print -r -- "T1C"; return 0
fi
if [[ "$s" == "t2w" || "$s" == "t2_" || "$s" == "t2_tse" || "$s" == "t2tse" || "$s" == "tse" ]]; then
print -r -- "T2"; return 0
fi
if [[ "$s" == "t1w" || "$s" == "t1_" || "$s" == "mpr" || "$s" == "ffe" ]]; then
print -r -- "T1"; return 0
fi
print -r -- "UNK"
}
#NIfTI本体のみ対象(._* を除外)
find . -maxdepth 1 -type f ( -name ".nii" -o -name ".nii.gz" ) ! -name "._*" -print0 |
while IFS= read -r -d '' path; do
f="${path#./}"
base="$(strip_nii_ext "$f")"
pid="$(get_pid "$base")"
ymd="$(get_ymd "$base")" || continue
mod="$(infer_mod_3 "$base")"
[[ "$mod" == "UNK" ]] && { print -u2 "SKIP (mod=UNK): $f"; continue; }
newbase="${pid}${ymd}${mod}"
#1) NIfTIをリネーム
if [[ "$f" == *.nii.gz ]]; then
newnii="${newbase}.nii.gz"
else
newnii="${newbase}.nii"
fi
if [[ -e "$newnii" && "$f" != "$newnii" ]]; then
print -u2 "ERROR (target exists): $newnii <-- from $f"
continue
fi
if (( DRYRUN )); then
print "DRYRUN: $f -> $newnii"
else
[[ "$f" != "$newnii" ]] && /bin/mv -v -- "$f" "$newnii"
fi
#2) 同名jsonがあれば追従リネーム(._json は無視)
oldjson="${base}.json"
newjson="${newbase}.json"
if [[ -e "$oldjson" ]]; then
if [[ -e "$newjson" && "$oldjson" != "$newjson" ]]; then
print -u2 "ERROR (target exists): $newjson <-- from $oldjson"
else
if (( DRYRUN )); then
print "DRYRUN: $oldjson -> $newjson"
else
[[ "$oldjson" != "$newjson" ]] && /bin/mv -v -- "$oldjson" "$newjson"
fi
fi
fi
done
て感じ。

第一段階終了。
第二段階は日付→基準日判定

変換テーブルを作る。
これは流石に手作業が必要か?
抜き出して条件分岐で設定も可能性あるか。
(別案件として保留)
テーブルに従って日付をリネームするスクリプト
前提:data_map.tsvが準備できている。
チャッピーがわでちょっとハマったっぽい。試行錯誤をくりかえし、sed awkでなんとかなった様子です。
#!/usr/bin/env zsh
set -euo pipefail
setopt null_glob
DRYRUN=1
if [[ "${1:-}" == "--run" ]]; then
DRYRUN=0
fi
SCRIPT_DIR="${0:A:h}"
MAPFILE="${SCRIPT_DIR}/date_map.tsv"
if [[ ! -f "$MAPFILE" ]]; then
print -u2 "ERROR: mapping table not found: $MAPFILE"
exit 1
fi
strip_ext() {
local f="$1"
if [[ "$f" == *.nii.gz ]]; then
print -r -- "${f%.nii.gz}"
elif [[ "$f" == *.nii ]]; then
print -r -- "${f%.nii}"
elif [[ "$f" == *.json ]]; then
print -r -- "${f%.json}"
else
print -r -- "$f"
fi
}
add_ext() {
local base="$1" orig="$2"
if [[ "$orig" == *.nii.gz ]]; then
print -r -- "${base}.nii.gz"
elif [[ "$orig" == *.nii ]]; then
print -r -- "${base}.nii"
elif [[ "$orig" == *.json ]]; then
print -r -- "${base}.json"
else
print -r -- "$orig"
fi
}
ymd -> label をTSVから取得(コメント行は無視)
lookup_label() {
local ymd="$1"
/usr/bin/awk -F'\t' -v d="$ymd" '
$0 ~ /^#/ {next}
$1 == d {print $2; exit}
' "$MAPFILE"
}
while IFS= read -r -d '' path; do
f="${path#./}"
base="$(strip_ext "$f")"
期待形式:PID_YYYYMMDD_MOD(後ろに _... があっても保持)
if [[ "$base" =~ '^([A-Za-z0-9]+)([0-9]{8})(T1C|T1|T2)(_.+)?$' ]]; then
pid="$match[1]"
ymd="$match[2]"
mod="$match[3]"
tail="${match[4]:-}"
else
continue
fi
label="$(lookup_label "$ymd")"
if [[ -z "${label:-}" ]]; then
print -u2 "SKIP (date not in map): $f (ymd=$ymd)"
continue
fi
newbase="${pid}${label}${mod}${tail}"
new="$(add_ext "$newbase" "$f")"
[[ "$f" == "$new" ]] && continue
if [[ -e "$new" ]]; then
print -u2 "ERROR (target exists): $new <-- from $f"
continue
fi
if (( DRYRUN )); then
print "DRYRUN: $f -> $new"
else
/bin/mv -v -- "$f" "$new"
fi
done < <(
/usr/bin/find . -maxdepth 1 -type f
( -name ".nii" -o -name ".nii.gz" -o -name ".json" )
! -name "._" ! -name ".DS_Store" -print0
)
