0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

<bash: find コマンド> 第一引数に指定したディレクトリ配下から、第二引数以降に一致するファイル・フォルダを除いて削除する

Last updated at Posted at 2024-12-29
実行は自己責任でお願いします!( . から始まるファイルも消えます)
詳細表示版
alias del='eval "set -f" "# $-" && SET="$_" DelEx';
function DelEx () {
    [[ $SET == *f* ]] || set +o noglob
    # 未定義変数チェック
    { 
        set -u;
        local ErrMsg="This function requires arguments.";
        local Usage="Usage: del <path> [<name to exclude> <name to exclude> ...]";
        (: "${1:?"${ErrMsg}${IFS}${Usage}${IFS}"}");
        local ErrLvl=$?;
        [[ $SET == *u* ]] || set +o nounset;
        [[ $ErrLvl -eq 1 ]] && return 1;
    } 
    # 第一引数を絶対パスに変更
    local Path="$1"
    Path="$(realpath -- "$Path")"
    [[ "$Path" == "/" ]] && {
        echo "Cannot execute.";
        return 1;
    }
    # 残りの引数を find で扱える形に調整
    local N=2 Arg=() Escaped Args=()
    while [[ "$N" -le "$#" ]]; do
        Arg[$N]="$N"
        Escaped=$(perl -e "print quotemeta('${!Arg[$N]}');")
        Args+=(! -regex ".*/${Escaped}\(/.*\|\)")
       ((N++))
    done
    # 第一引数が存在するパスであれば削除を実行
    echo "[Summary]"
    echo "Target path: "$'\n'"  '$Path'"
    [[ -d $Path ]] && {
        [[ $1 =~ ^\.+(/+\.*)*$ ]] || { find "$Path" -xdev -maxdepth 0 -delete 2>/dev/null && return; }
        echo "Name to exclude: ";
        local Nest;
        Nest=("${Arg[@]/#/\$\{}");
        eval echo '"  "'"${Nest[@]/%/@Q\}}";
        echo $'\n'"[Verbose]";
        find "$Path" -xdev -depth ! -path "$Path" -regextype findutils-default "${Args[@]}" -print -delete;
        return;
    }
    [[ -f $Path ]] && {
        find "$Path" -xdev -maxdepth 0 -delete;
        return;
    }
    # パスがディレクトリでもファイルでもなかった場合
    echo "failed."
    return 255
}

詳細非表示
# bash のワイルドカードによるパス名展開を無効化(/* 対策)
# find による正規表現の解釈も perl で無効化
alias del='eval "set -f" "# $-" && SET="$_" DelEx';

# 正規表現について
# "." :任意の1文字
# "*" :直前の文字に0回以上マッチ(最長一致)
# "|" :OR条件
function DelEx () {
    [[ $SET == *f* ]] || set +o noglob
    # 未定義変数チェック
    { 
        set -u;
        local ErrMsg="This function requires arguments.";
        local Usage="Usage: del <path> [<name to exclude> <name to exclude> ...]";
        (: "${1:?"${ErrMsg}${IFS}${Usage}${IFS}"}");
        local ErrLvl=$?;
        [[ $SET == *u* ]] || set +o nounset;
        [[ $ErrLvl -eq 1 ]] && return 1;
    } 
    # 第一引数を絶対パスに変更
    local Path="$1"
    Path="$(realpath -- "$Path")"
    [[ "$Path" == "/" ]] && {
        echo "Cannot execute.";
        return 1;
    }
    # 残りの引数を find で扱える形に調整
    local N=2 Arg=() Escaped Args=()
    while [[ "$N" -le "$#" ]]; do
        Arg[$N]="$N"
        Escaped=$(perl -e "print quotemeta('${!Arg[$N]}');")
        Args+=(! -regex ".*/${Escaped}\(/.*\|\)")
       ((N++))
    done
    # 第一引数が存在するパスであれば削除を実行
    [[ -d $Path ]] && {
        [[ $1 =~ ^\.+(/+\.*)*$ ]] || { find "$Path" -xdev -maxdepth 0 -delete 2>/dev/null && return; }
        find "$Path" -xdev -depth ! -path "$Path" -regextype findutils-default "${Args[@]}" -delete 2> >(grep -v "Directory not empty" >&2);
        return;
    }
    [[ -f $Path ]] && {
        find "$Path" -xdev -maxdepth 0 -delete;
        return;
    }
    # パスがディレクトリでもファイルでもなかった場合
    return 255
}
bash
# 実行例
mkdir -p ./target/{"delete folder","exclude folder",other_folder}
touch ./target/{'.*[a-z]+',.file1,.file2} ./target/"delete folder"/{file3,file4} ./target/"exclude folder"/{file5,file6} ./target/other_folder/{file7,file8}
tree -a ./target
   ./target
   ├── .*[a-z]+
   ├── .file1
   ├── .file2
   ├── delete folder
   │   ├── file3
   │   └── file4
   ├── exclude folder
   │   ├── file5
   │   └── file6
   └── other_folder
       ├── file7
       └── file8
   3 directories, 9 files
    
set -x
del ./target .*[a-z]+ "exclude folder" file8
set +x
tree -a ./target
   ./target
   ├── .*[a-z]+
   ├── exclude folder
   │   ├── file5
   │   └── file6
   └── other_folder
       └── file8
   2 directories, 4 files



# 実行結果
del ./target .*[a-z]+ "exclude folder" file8
   + set -f
   + DelEx ./target '.*[a-z]+' 'exclude folder' file8
   + set +o noglob
   + set -o nounset
   + ErrMsg='This function requires arguments.'
   + Usage='Usage: del <path> [<name to exclude> <name to exclude> ...]'
   + : ./target
   + Path=./target
   ++ realpath -- ./target
   + Path=/home/$(whoami)/target
   + [[ /home/$(whoami)/target == \/ ]]
   + unset Arg Args
   + N=2
   + Arg=()
   + Args=()
   + [[ 2 -le 4 ]]
   + Arg[$N]=2
   ++ perl -e 'print quotemeta('\''.*[a-z]+'\'');'
   + Escaped='\.\*\[a\-z\]\+'
   + Args+=(! -regex ".*/${Escaped}\(/.*\|\)")
   + (( N++ ))
   + [[ 3 -le 4 ]]
   + Arg[$N]=3
   ++ perl -e 'print quotemeta('\''exclude folder'\'');'
   + Escaped='exclude\ folder'
   + Args+=(! -regex ".*/${Escaped}\(/.*\|\)")
   + (( N++ ))
   + [[ 4 -le 4 ]]
   + Arg[$N]=4
   ++ perl -e 'print quotemeta('\''file8'\'');'
   + Escaped=file8
   + Args+=(! -regex ".*/${Escaped}\(/.*\|\)")
   + (( N++ ))
   + [[ 5 -le 4 ]]
   + [[ -d /home/$(whoami)/target ]]
   + [[ ./target =~ ^\.+$ ]]
   + [[ ./target =~ ^\.+(/+\.*)+$ ]]
   + find /home/$(whoami)/target -xdev -maxdepth 0 -delete
   + find /home/$(whoami)/target -xdev -depth '!' -path /home/$(whoami)/target -regextype findutils-default '!' -regex '.*/\.\*\[a\-z\]\+\(/.*\|\)' '!' -regex '.*/exclude\ folder\(/.*\|\)' '!' -regex '.*/file8\(/.*\|\)' -delete
   ++ grep --color=auto -v 'Directory not empty'
   + return
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?