Bash - 再帰的なディレクトリ/ファイルの名前変更

Bash - 再帰的なディレクトリ/ファイルの名前変更

ファイルとディレクトリのすべてのスペースを再帰的に置き換える次のスクリプトがあります。

################### SETUP VARIABLES #######################
number=0                    # Number of renamed.
number_not=0                # Number of not renamed.
IFS=$'\n'
array=( `find ./ -type d` ) # Find catalogs recursively.


######################## GO ###############################
# Reverse cycle.
for (( i = ${#array[@]}; i; )); do
     # Go in to catalog.
     pushd "${array[--i]}" >/dev/null 2>&1
     # Search of all files in the current directory.
     for name in *
     do
             # Check for spaces in names of files and directories.
             echo "$name" | grep -q " "
             if [ $? -eq 0 ]
             then
                # Replacing spaces with underscores.
                newname=`echo $name | sed -e "s/ /_/g"`
                if [ -e $newname ]
                then
                        let "number_not +=1"
                        echo " Not renaming: $name"
                else
                        # Plus one to number.
                        let "number += 1"
                        # Message about rename.
                        echo "$number Renaming: $name"
                        # Rename.
                        mv "$name" "$newname"
                fi
             fi
     done
     # Go back.
     popd >/dev/null 2>&1
done

echo -en "\n All operations is complited."

if [ "$number_not" -ne "0" ]
  then echo -en "\n $number_not not renamed."
fi

if [ "$number" -eq "0" ]
  then echo -en "\n Nothing been renamed.\n"
elif [ "$number" -eq "1" ]
   then echo -en "\n $number renamed.\n"
   else echo -en "\n Renamed files and catalogs: $number\n"
fi

exit 0

配列をディレクトリで埋める方法で動作します。

array=( `find ./ -type d` ) # Find catalogs recursively.

このスクリプトを特定のディレクトリで強制的に動作させるにはどうすればよいですか?

array=( `find /my/start/directory/ -type d` ) # Find catalogs recursively.

私はそれが正しいことを再確認し、誤ってサーバー上のすべてのファイル名を変更したくないので、(単に実行するのではなく)ここに尋ねます!

ベストアンサー1

mvコマンドをコメントアウトして実行し、提案された変更でスクリプトをテストできます。スクリプトであまりにも多くのことが行われているので、すぐに大丈夫だとは言えませんが、array現在のスクリプトが有効な場合は混乱する可能性があります(明らかに改行文字を含むディレクトリ名がない、配列がめちゃくちゃになった、または名前が開始されません)。ダッシュを使用mvし、echoいくつかの場所では)大丈夫だろうと思います。


ディレクトリやその他のファイルのファイル名のスペースをアンダースコアに繰り返し変更します。

topdir=.
find "$topdir" -depth -name "* *" -exec bash -c '
    for pathname do
        # $pathname will have at least one space in it
        newname=${pathname##*/}  # get basename
        newname=${newname// /_}  # replace spaces with underscores
        printf "Would move %s to %s\n" "$pathname" "${pathname%/*}/$newname"
        # mv "$pathname" "${pathname%/*}/$newname"
     done' bash {} +

$topdir名前の内または下に少なくとも1つのスペースを含むすべての項目を見つけます。これらのパス名を収集してインラインbashスクリプトに提供します。このスクリプトは、各パス名のファイル名部分を抽出し、スペースを下線で置き換えます。実際の作業は安全上の理由からmv注釈付けされています。

-depthまだアクセスしていないディレクトリの名前を変更したくないため、このオプションが必要です。これにより、findディレクトリ階層の深さ優先探索が実行されます。

使用されるパラメータの置換:

  • ${variable##*/}:値の最後のスラッシュの前のすべての項目を削除しますvariable。とほぼ同じです$( basename "$variable" )
  • ${variable%/*}:最後のスラッシュの後のすべてのエントリを削除します。とほぼ同じです$( dirname "$variable" )
  • ${variable//pattern/replacement}pattern一致する値のすべてを置き換えます(これは拡張です)。replacementvariablebash

新しいファイル名がすでに存在するかどうかを確認しません。これは内部スクリプトで簡単に実行できますbash

if [ -e "${pathname%/*}/$newname" ]; then
    printf "Will not rename %s, new name exists\n" "$pathname" >&2
else
    printf "Would move %s to %s\n" "$pathname" "${pathname%/*}/$newname"
    # mv "$pathname" "${pathname%/*}/$newname"
fi

テスト:

$ tree
.
|-- a directory
|   `-- yet another file
|-- script.sh
|-- some file
`-- some other file

1 directory, 4 files

$ sh script.sh
Would move ./some file to ./some_file
Would move ./some other file to ./some_other_file
Would move ./a directory/yet another file to ./a directory/yet_another_file
Would move ./a directory to ./a_directory

関連:

おすすめ記事