次のファイル構造があります。
- いくつかのディレクトリ
- 一部のファイル.txt
- ここに別のファイルがあります。 .log
- .mp3 ファイルもあります。
- その他のディレクトリ
- 他のfile.txtと一緒に
- ルートレベル file.txt
- ルートレベルの他のファイル.ext
今私が望むのは、パターン/代替ペアを含む別のファイルを入力として使用して、そのファイルに基づいてそのファイルの名前を繰り返し変更する小さなスクリプトを実行することです。これにより、すべての「another」(大文字と小文字を区別しない)が「foo」に置き換えられるか、すべての「some」が「bar」に置き換えられます。
私はファイルを繰り返してその入力ファイルを読み取るためにいくつかの方法を試しましたが、何も機能せず、最終的に誤ってテストスクリプトを上書きしました。しかしls
、、、while
がsed
多くmv
使われています。
自分で知らない2つは、ファイル名のスペースを処理する方法と、以前のパターンマッチングで名前が変更されたファイルを処理しない方法です。
たぶんあなたが私に正しい方向を伝えることができますか?
答え1
TOP="`pwd -P`" \
find . -type d -exec sh -c '
for d
do
cd "$d" && \
find . ! -name . -prune -type f -exec sh -c '\''
while IFS=\; read -r pat repl
do
rename "s/$pat/$repl/g" "$@"
N=$#
for unmoved
do
if [ -f "$unmoved" ]
then
set X ${1+"$@"} "$unmoved"
shift
fi
done
shift "$N"
case $# in 0 ) break ;; esac
done < patterns.csv
'\'' x \{\} +
cd "$TOP"
done
' x {} +
find
ネットワークディレクトリを設定して飲み込むだけですsh
。これにより、呼び出し回数が最小限に抑えられますsh
。find
各ディレクトリのネットワークファイルをregular
奥行きレベル1に設定し、sh
おしゃべりをしてください。これにより、rename
ユーティリティの呼び出し回数が最小限に抑えられます。while
個々のペアで読み取り、pattern <-> replacement
すべてのファイルに適用するようにループを設定しますregular
。- 進行中
rename
-イギリスrename
処理後もファイルがまだ存在するかどうかを記録します。ファイルがまだ存在するということは、何らかの理由で名前を変更することはできず、次の反復で試行されることを意味しますpat/repl
。 OTOH、ファイル名が正常に変更された場合は、pat/repl
コマンドライン引数リストからファイルを削除して、ファイルに次の反復を適用しません。
答え2
rPairs="/tmp/rename_pairs" \
find . -type f -exec sh -c '
while read -r old new; do
rename "s/$old/$new/i" "$@"
done < "$rPairs"
' x {} +
名前の変更 ペア ファイルに ASCII 以外の文字がなく、ファイルが検索パスから離れているとします。
答え3
Rakesh Sharmaの回答に従って、より多くの努力をし、しばらく寝てから正しい方向を見つけました。
ついに私は次のスクリプトを思いついた。
#!/bin/bash
while IFS=";" read pattern replacement
do
if [[ ! -z $pattern ]]
then
echo "Checking files for pattern '$pattern'."
find ./files -name "*$pattern*" -type f | while read fpath
do
fname=$(basename "$fpath")
dname=$(dirname "$fpath")
echo " Found file '$fname' in directory '$dname'. Renaming to '${fname/$pattern/$replacement}'."
mv -- "$fpath" "$dname/${fname/$pattern/$replacement}"
done
fi
done < patterns.csv
ファイルを読み込み、塗りつぶしpattern.csv
と変数行を繰り返します。 2番目のステップでは、現在のパターンと一致するディレクトリ内のすべてのファイルを探します。これは、2番目のパターンが一致したときにファイル名を変更し直すのを防ぐために必要です。これは失敗するためです。最後に、ファイルを含むディレクトリの名前を変更するためにシェルパラメータ置換を使用するのではなく、ファイル自体の名前のみを変更します。$pattern
$replacement
./files
うまくいかないのは、大文字と小文字を区別しない一致を置き換えることです。しかし、私はそれで生きることができます。
答え4
覚えておくべき重要なことは、ディレクトリツリーをナビゲートするプロセスが遅いので、一度だけ行うことです。私たちが最初にやりたいことは、find
ツリーのディレクトリを見てみることです。各ディレクトリについて、regular files
その下のすべてのディレクトリを探します(ここでは再帰はありません)。その後、成功したかどうかを記録しながら、これらのファイル名に名前変更変換を適用します。成功したら、whileループを終了して、次のpatt / replがファイルに適用されないようにします。
tempd="`mktemp -d`" \
find . -type d -exec sh -c '
cd "$1" && \
for f in ./*
do
[ -f "$f" ] || continue
while IFS=\; read -r patt repl
do
case $f in
./*"$patt"* )
rename -v "s/$patt/$repl/g" "$f" 2>&1 | tee "$tempd/$f"
case $(< "$tempf/$f") in "$f renamed "* ) break ;; esac ;;
esac
done < /tmp/patterns.csv
done
' {} {} \;