log_<date>.txt
ネストされたディレクトリに同じ命名法を共有するファイルが散在していますroot
。<date>
ファイルが作成された日付はYYYYmmddHHMMの形式でどこにありますか。コード互換性の問題のため、すべてのファイルの名前を次のように変更したいと思います。<date>_log.txt
式をキャプチャする必要があることはわかっています<date>
が、bash でそれをどのように行うのでしょうか? また、ネストされたディレクトリでそれをどのように行うのでしょうか?
答え1
シェル変数 にこれらのファイルの 1 つの名前があるとしますname
。log_
変数の値から ビットを削除するには を使用し${name#log_}
、.txt
ビットを削除するには を使用します。残っているのは日付であり、その形式は基本的に重要ではありません。削除された値を取得してその末尾に追加して新しい名前を作成するのは${name%.txt}
簡単です。_log_.txt
単一のディレクトリ内のファイルに対してこれを行うには、ループを使用します。変数の値の先頭のディレクトリ名も削除する必要があることに注意してください。
shopt -s nullglob
for name in root/log_*.txt; do
newname=root/${name#root/log_} # remove prefix, add root/ back
newname=${newname%.txt}_log.txt # remove suffix, add _log.txt back
printf 'Would move "%s" to "%s"\n' "$name" "$newname"
# mv -i "$name" "$newname"
done
安全のため、実際のコマンドはコメントアウトしましたmv
。まずは一度テスト実行して何が起こるかを確認してください。
シェルnullglob
オプションはbash
シェルを作成します取り除くlog_*.txt
一致しないパターンを展開せずに残すのではなく、展開せずに残します。つまり、指定されたディレクトリにファイルがない場合、ループはまったく実行されません。
これは、現在のディレクトリ(現在のディレクトリを含む)の下の任意のファイルに再帰的に適用できます。多かれ少なかれループするパターンを変更するだけです:
shopt -s globstar nullglob
for name in ./**/log_*.txt; do
dirpath=${name%/*} # get path of directory
newname=$dirpath/${name#$dirpath/log_} # remove prefix, add directory path back
newname=${newname%.txt}_log.txt # remove suffix, add _log.txt back
printf 'Would move "%s" to "%s"\n' "$name" "$newname"
# mv -i "$name" "$newname"
done
その他の変更には、globstar
シェル オプションを有効にすることが含まれます**
。これにより、サブディレクトリまで一致させることができます。また、ディレクトリ パスを選択して、新しい名前の先頭に追加できるようにしました。
find
ループへの入力を生成するためにも使用できます:
find . -type f -name 'log_*.txt' -exec sh -c '
for name do
dirpath=${name%/*} # get path of directory
newname=$dirpath/${name#$dirpath/log_} # remove prefix, add directory path back
newname=${newname%.txt}_log.txt # remove suffix, add _log.txt back
printf "Would move \"%s\" to \"%s\"\n" "$name" "$newname"
# mv -i "$name" "$newname"
done' sh {} +
これにより、現在のディレクトリまたはその下で名前が一致するすべての通常ファイルが検索されlog_*.txt
、それらのファイルがバッチでインラインsh -c
スクリプトに渡されます。このインライン スクリプトは、基本的に上記の 2 番目のバリエーションのループと同じ作業を実行します。
答え2
zsh
最善の方法は、のようなバッチ ファイル名変更ツールzmv
、mmv
または の Perl ベースのバリアントのいずれかを使用することですrename
。
zsh << 'EOF'
autoload zmv
zmv 'log_(*).txt' '${1}_log.txt'
EOF
または
prename 's/log_(.*)\.txt/${1}_log.txt/' log*.txt