ファイルのパーミッションをまとめて変える


0. Contents

1. Concept
2. Script Source
3. How to Use


1. Concept

USB メモリなどを経由してファイルをやり取りすると
パーミッションがおかしくなるケースが良くあるが、
chmod -R を使うと全てのファイルやディレクトリが対象に
なってしまうので使い勝手が悪い。

そこで、特定のパーミッションのファイル (ディレクトリ) のみを
対象に処理を行うサブルーチンを作成した。


2. Script Source

ソースは以下の通り (ダウンロード)。

#! /usr/bin/env bash

function cfp(){
## 変数のセット
  local {D,R,L}File COpt Dir='.'
  declare -a DPerm=( 777 755 ) FPerm=( 777 644 )

## 引数をチェック
  while (( $# > 0 )) ; do
    case "$1" in
      -d)
        if [[ -n "$2" && -n "$3" ]] ; then
          DPerm=( "$2" "$3" )

        else
          echo "error: $FUNCNAME: $1: No argument." 1>&2
          return 1
        fi && shift 3
      ;;

      -f)
        if [[ -n "$2" && -n "$3" ]] ; then
          FPerm=( "$2" "$3" )

        else
          echo "error: $FUNCNAME: $1: No argument." 1>&2
          return 1
        fi && shift 3
      ;;

      -t)
        case "$2" in
          s) DPerm=( 777 755 ) FPerm=( 777 644 ) ;;

          o) DPerm=( 755 700 ) FPerm=( 644 600 ) ;;

          g) DPerm=( 700 755 ) FPerm=( 600 644 ) ;;

          c) DPerm=() FPerm=( 755 644 ) ;;

          x) DPerm=() FPerm=( 644 755 ) ;;

          *)
            echo "error: $FUNCNAME: $1 $2: Invalid argument." 1>&2
            return 1
          ;;
        esac && shift 2
      ;;

      --depth)
        if [ "$2" -gt 0 ] 2>&- ; then
          COpt="-maxdepth $2"

        else
          echo "error: $FUNCNAME: $1 $2: Invalid argument." 1>&2
          return 1
        fi && shift 2
      ;;

      *)
        if [[ -d "$1" ]] ; then
          Dir=${1%/}

        else
          echo "error: $FUNCNAME: $1 $2: Invalid argument." 1>&2
          return 1
        fi && shift
      ;;
    esac
  done

## 処理対象ファイルの検索
  echo -n "$FUNCNAME: Checking '$Dir/'...  "
  [[ -n "${FPerm[0]}" ]] && RFile=$( find "$Dir" $COpt -type f -perm "${FPerm[0]}" & )
  [[ -n "${DPerm[0]}" ]] && DFile=$( find "$Dir" $COpt -type d -perm "${DPerm[0]}" & )
  wait

  LFile=$(
    [[ -n "$DFile" ]] && {
      echo "Dir: ${DPerm[0]} -> ${DPerm[1]}"
      echo "$DFile"
      [[ -n "$RFile" ]] && echo
    }
    [[ -n "$RFile" ]] && {
      echo "File: ${FPerm[0]} -> ${FPerm[1]}"
      echo "$RFile"
    }
  )
  [[ -n "$LFile" ]] && echo 'done.' || {
    echo 'Not found.' 1>&2
    return 1
  }

## 確認後, 変更
  echo -e "\n${LFile}\n"
  read -p "$FUNCNAME: Change permission Now ? [y/N] : "
  [[ "$REPLY" == [yY] ]] && echo || {
    echo "$FUNCNAME: quit." 1>&2
    return 1
  }

  [[ -n "$RFile" ]] && {
    find "$Dir" $COpt -type f -perm "${FPerm[0]}" -print0 |
      xargs -0 chmod -v "${FPerm[1]}" &
  }
  [[ -n "$DFile" ]] && {
    find "$Dir" $COpt -type d -perm "${DPerm[0]}" -print0 |
      xargs -0 chmod -v "${DPerm[1]}" &
  }
  wait && echo -e "\n$FUNCNAME: done."
}
cfp "$@"


3. How to Use

上記のソースをそのまま貼り付ければ OK。
USAGE、OPTION は以下の通り。

USAGE: cfp (Options) (Directory)

   -d [From] [To]
      : set directory permission (default: 777 -> 755)

   -f [From] [To]
      : set file permission (default: 777 -> 644)

   -t [Type]
      : set preset mode (default: s)
          s : Secure	(D: 777 -> 755, F: 777 -> 644)
          o : Ower	(D: 755 -> 700, F: 644 -> 600)
          g : Group	(D: 700 -> 755, F: 600 -> 644)
          c : Cut X	(F: 755 -> 644)
          x : Plus X	(F: 644 -> 755)

   --depth [Num]
      : set maxdepth for find

   [Dir]
      : set check dir (default: $PWD)