ファイルからアポストロフィを削除する必要があります。私はいくつかのアプローチを試しました。スタック交換。
私はSynology NASを使用しているので、PythonやPerlがなく、特定のディレクトリを除外する必要があります(find -prune)。
次の find コマンドはテスト中に通常動作するようです(エコーを使用)。
find . -depth \( -type d -name "@*" -o -name "*#recycle*" -o -name "*SynoResource*" -prune \) -o \( -name "*\'*" -execdir bash -c 'for f; do echo mv ${f/\\\'/\\\\'} `echo $f | sed 's/\\\'/X/g'`; done' _ {} + \)
「911's.zip」などのファイルの場合、アポストロフィ 'をXに置き換えると次のようになります(上記のコマンドを使用)。
mv ./911's.zip ./911Xs.zip
コマンドを実行するために「echo」を削除すると、次のエラーが発生します。
mv: target '911Xs.zip' is not a directory
対話型シェルでは、次のようにファイル名を変更できます。
mv 911\'s.zip 911Xs.zip
もちろん'(のような\'sが複数ある場合でも${f/\'/X}
)脱出しようとしましたが、うまくいきませんでした。
どんなアイデアがありますか?
ありがとう、
ゲイリー
答え1
いくつかの問題:
- プロセスが最初に残るため、
-prune
結合できないため、ディレクトリの内容全体が処理された後は遅すぎるため、何の効果もありません。-depth
-depth
-prune
- あなたの
-prune
場所が間違っています。どこに置くと、一致するファイルにのみ適用されます-name "*SynoResource*"
。同じです。-type d
にのみ適用されます-name "@*"
。 - パラメータ拡張とコマンド置換に二重引用符がないため、分割+グローブが発生します。
echo
通常、任意のデータの出力には使用できません。'
内部に一重引用符文字列を含めることはできません。'
リテラル値をコマンドに渡す必要がある場合は、別のシェル引用演算子("..."
またはバックスラッシュ)を使用して一重引用符の外に引用する必要があります。'
それは彼らにとって特別なものではなくmv
、それを避ける必要もありません。これはシェルに特有で強力な参照演算子です。sed
find
$(...)
廃止予定の代わりに使用する必要があります`...`
(バックスラッシュが含まれる場合はより複雑になります)。
だからここにあります:
LC_ALL=C Q="'" find . -depth \
! -path '*/@*' \
! -path '*#recycle*' \
! -path '*SynoResource*' \
-name "*'*" -execdir bash -c '
for file do
mv -i -- "$file" "${file//$Q/X}"
done' bash {} +
ここ-prune
では動作しないため(GNUでも呼び出されます)-depth
を使用して、フルパスに基づいて除外されたディレクトリ内のファイルをフィルタリングします。ただし、これはパフォーマンスの観点から理想的ではないディレクトリに移動することを意味します。-path
-wholename
find
find
を使用することは、デフォルトの名前を変更するだけでよいことを意味しますが、sを含むファイルを含むすべてのディレクトリで少なくとも1つを実行-execdir
することになります。または、次のことができます。bash
'
LC_ALL=C Q="'" find . -depth \
! -path '*/@*' \
! -path '*#recycle*' \
! -path '*SynoResource*' \
-name "*'*" -exec bash -c '
for file do
dir=${file%/*} base=${file##*/}
mv -i -- "$file" "$dir/${base//$Q/X}"
done' bash {} +
これにより、スクリプトの実行中に誰かがファイルとディレクトリの名前を変更するのに対してより効率的ですが、安全性が低くなります。
練習実行の場合は、mv
コマンドを次のように置き換えることができます。
(PS4="Would run"; set -x; : mv -- "$file" "$dir/${base//$Q/X}")
echo
bash
これは、トレース出力であいまいにならないようにするために必要な場所に引用符を使用するため、asを使用するよりも優れています。トレース出力は、同じコマンドを実行するために使用できる有効なシェルコードのように見えます。
ここで-exec
置き換えを使用すると、-execdir
名前が変更されたファイルを明確に追跡することもできます。
ディレクトリの深さを最初に使用しますが、処理を続行するには、出力で-prune
GNU(および利用可能な場合はGNU)を使用してそれを反転する別の方法があります。tac -s ''
xargs
find -print0
LC_ALL=C find . -depth \
'(' -name '@*' -o \
-name '*#recycle*' -o \
-name '*SynoResource*' \
')' -type d -prune -o \
-name "*'*" -print0 |
tac -s '' |
Q="'" xargs -r0 bash -c '
for file do
dir=${file%/*} base=${file##*/}
mv -i -- "$file" "$dir/${base//$Q/X}"
done' bash {} +
GNUはありませんが、bashがtac
4.4xargs
以上の場合は、次のこともできます。
LC_ALL=C find . -depth \
'(' -name '@*' -o \
-name '*#recycle*' -o \
-name '*SynoResource*' \
')' -type d -prune -o \
-name "*'*" -print0 |
Q="'" bash -c '
readarray -td "" files &&
for (( i = ${#files[@]} - 1; i >= 0; i-- )); do
file=${files[i]}
dir=${file%/*} base=${file##*/}
mv -i -- "$file" "$dir/${base//$Q/X}"
done' bash {} +
(まだテストしたことはありませんので参考にしてください。)