作曲・指導・C言語・Linux

金沢音楽制作

金沢音楽制作では、楽曲・楽譜の制作と、作曲や写譜などレッスンを行っています。

rms

rmの皮をかぶったmvコマンド、rmsです(sはセキュアの意)。あまりにも不用意にrmでファイルを消してしまうので、ログを付けて別ディレクトリに一時保管するスクリプトです。セキュアと謳いながら、そのまま使うのは危険ですので、プログラミングの参考程度にしてください。また、筆者が知らないだけで、もっとよい方法があるかも知れません。

環境:macOS Big Sur

実行画面

rmsは、前述したようにmvを呼び出しているだけなので、対象がディレクトリでも-rオプションは不要です。実行すると、ホームディレクトリにrms_trash(任意で変更可能)が作成されます。そして、その中に%Y-%m-%d/%H%M%S-%Nで区分けされたディレクトリが作成され、そこに移動します。

$ pwd
/Users/${USER}/Google\ Drive/
$ rms number_dir/ ~/hoge_file
to /Users/${USER}/rms_trash/2021-11-11/163432-010796000

移動先のディレクトリを確認すると、確かに移動されていることが分かります。ファイルネームに移動元のパスが付きます。ファイル名に/は使えないので、@に置換しています。

$ ls ~/rms_trash/2021-11-11/163432-010796000/
@Users@${USER}@hoge@file  '@Users@${USER}@Google\ Drive@number_dir'   log.txt

ログファイル、log.txtが作成されます。ファイルの移動元パスが記述されます。

$ less log.txt
/Users/${USER}/Google\ Drive/number_dir
/Users/${USER}/hoge_file

何かしらの事情で同じ時刻、つまり同名のディレクトリが発生した場合、${RANDOM}で、ディレクトリ名の末尾に数字が付与されます。下記の例では、_1347が付与されています。

$ ls ~/rms_trash/2021-11-11
163432-010796000  163432-010796000_1347

オプションとして--deleteがあります。実行すると、~/rms_trash/以下がすべて削除されます。危険なので、手動で確認しながら消した方が安全かも知れません。

$ rms --delete
DELETE /Users/${USER}/rms_trash/*
Y/n :y
/Users/${USER}/rms_trash/* is deleted
$ ls ~/rms_trash/*
$

ソースコード

#!/bin/bash

declare -a argv=$@
declare -i argc=$#

declare -r TRASH_DIR=${HOME}/rms_trash
declare -r DATE_Ymd=$(date '+%Y-%m-%d')
declare -r DATE_HMSN=$(date '+%H%M%S-%N')
declare -r TARGET_PASS=${TRASH_DIR}/${DATE_Ymd}/${DATE_HMSN}

fn_main() {
  fn_is_argment && fn_get_option && fn_make_dir

  local -i error=0
  for i in ${argv[@]}; do
    fn_is_file ${i} && fn_move_file ${i} || ((++error)) 
  done

  if [ ${argc} -eq ${error} ]; then
    echo 'All files not found'
    return 1
  fi

  echo "to ${TARGET_PASS}"

  return 0
}

fn_is_argment() {
  if [ ${argc} = 0 ]; then
    fn_usage
    exit 1
  fi

  return 0
}

fn_get_option() {
  if [ "${argv[0]}" = '--delete' ]; then
    fn_remove_rms_trash
    exit 0
  fi

  return 0
}

fn_make_dir() {
  if [ ! -d ${TARGET_PASS} ]; then
    mkdir -p ${TARGET_PASS}
  else
    local -i rand=${RANDOM}

    while :; do
      if [ ! -d ${TARGET_PASS}_${rand} ]; then
        mkdir ${TARGET_PASS}_${rand}
        break
      else
        rand=${RANDOM}
      fi
    done
  fi

  return 0
}

fn_is_file() {
  ls -d ${1} > /dev/null 2>&1

  if [ $? != 0 ]; then
    echo "${1} is not found"
    return 1
  fi

  return 0
}

fn_move_file() {
  local real_pass=$(readlink -f ${1})
  local -r delimiter='\@'
  local target=${TARGET_PASS}/${real_pass//\//${delimiter}}

  eval mv ${1} ${target// /\\ } > /dev/null 2>&1

  fn_make_log "${real_pass// /\\ }"

  return 0
}

fn_usage() {
  local -r SCRIPT_NAME=${0##*/}

  cat << EOF
Usage:
$ ./${SCRIPT_NAME} [file1] [file2] [file3] ...
  The argment file is moved to the ${TRASH_DIR}
  
options:
  --delete  Delete ${TRASH_DIR} files
$ ./${SCRIPT_NAME} --delete

EOF
}

fn_remove_rms_trash() {
  local buf

  echo "$ DELETE ${TRASH_DIR}/*"
  read -p "Y/n :" buf

  case ${buf} in
    [Yy])
      rm -r ${TRASH_DIR}/*
      echo "${TRASH_DIR}/* is deleted"
      ;;
  esac
}

fn_make_log() {
  echo ${1} >> ${TARGET_PASS}/log.txt
}


fn_main

# HASE Kazuaki <hase at hkmc.jp>

更新情報

  • 作成日:2021-11-12
  • 作成日:2022-05-02