487個のフォルダがあるというフォルダがあります/home/user/temps
。各フォルダにはThumb.pngというファイルがあります。
Thumb.pngという名前のすべてのファイルを別のフォルダにコピーし、元のフォルダに応じて名前を変更したいと思います。
答え1
ここにあります:
for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file/\/thumb/}"; done;
編集する:
ところで、一般的な通念はこうするのがfind
悪い考えだということです。単にシェル拡張を使用する方がより安定しています。また、これは仮説ですbash
が、安全な仮定だと思います:)
編集2:
明確にするために分析します。
# shell-expansion to loop specified files
for file in /home/user/temps/*/thumb.png; do
# replace 'temps' with 'new_folder' in the path
# '/home/temps/abc/thumb.png' becomes '/home/new_folder/abc/thumb.png'
new_file=${file/temps/new_folder};
# drop '/thumb' from the path
# '/home/new_folder/abc/thumb.png' becomes '/home/new_folder/abc.png'
cp "$file" "${new_file/\/thumb/}";
done;
${var/Pattern/Replacement}
詳細な工事情報をご確認いただけます。ここ。
この行の引用符は、cp
ファイル名のスペース、改行などを処理するために重要です。
答え2
このソリューションは、サブディレクトリとサブディレクトリのファイルを「フラット化」して、両方とも1つの大きなディレクトリに存在するようにします。新しいファイル名は元のパスを反映します。たとえばにtemps/dir/subdir/thumb.png
なりますnewdir/temps_dir_subdir_thumb.png
。
find temps/ -name "thumb.png" |
while IFS= read -r f do
cp -v "$f" "newdir/${f//\//_}"
done
ディレクトリtemps
がnewdir
存在する必要があります。そして、temps
コマンドはおよびの親ディレクトリで実行する必要がありますnewdir
。
このコマンドは1行で完了することもできます。
find temps/ -name "thumb.png" | while IFS= read -r f; do cp -v "$f" "newdir/${f//\//_}"; done
;
改行文字を含むセミコロン()に注意してください。
出力例
$ find temps/ -name "thumb.png" | while IFS= read -r f; do cp -v "$f" "newdir/${f//\//_}"; done
`temps/thumb.png' -> `newdir/temps_thumb.png'
`temps/dir3/thumb.png' -> `newdir/temps_dir3_thumb.png'
`temps/dir3/dir31/thumb.png' -> `newdir/temps_dir3_dir31_thumb.png'
`temps/dir3/dir32/thumb.png' -> `newdir/temps_dir3_dir32_thumb.png'
`temps/dir1/thumb.png' -> `newdir/temps_dir1_thumb.png'
`temps/dir2/thumb.png' -> `newdir/temps_dir2_thumb.png'
`temps/dir2/dir21/thumb.png' -> `newdir/temps_dir2_dir21_thumb.png'
わからない場合は、追加してecho
実行するcp
内容を確認してください。
find temps/ -name "thumb.png" | while IFS= read -r f; do echo cp -v "$f" "newdir/${f//\//_}"; done
説明する
これは次の方法で行うことができます。パラメータ拡張:${f//\//_}
。変数の内容f
(パスとファイル名を含む)を取得し、各項目/
を_
。
これは愚かなテキスト検索と置換です。 2つの異なるファイルが同じ名前で終わる場合は、ファイルの1つが上書きされます。
たとえば、2つのファイルtemps/dir/thumb.png
とtemps/dir_thumb.png
。どちらのファイルも名前がtemps_dir_thumb.png
. に変更されるため、1 つのファイルが失われます。失われるファイルは、find
ディスクに見つかった順序によって異なります。
義務的な賢明な警告:ファイル名に改行文字が含まれていると、このコマンドは激しくクラッシュします。
答え3
oneliner コマンドでファイルを検索、コピー、名前を変更できます。-sh 実行:
find /home/user/temps -name thumb.png \
-exec sh -c 'cp "{}" "$(basename "$(dirname "{}")")_$(basename "{}")"' \;
(追加の内容は"
コピーされたファイルを空白として扱うことです。)
オプション2- with xargs
(実行前に各コマンドを印刷できます):
find /home/user/temps -name thumb.png \
| xargs -I {} --verbose sh -c 'cp "{}" "$(basename "$(dirname "{}")")_$(basename "{}")"'
sh -c cp "temps/thumb.png" "$(デフォルト名 "$(dirname "temps/thumb.png")")_$(デフォルト名 "temps/thumb.png")"
sh -c cp "temps/dir one/thumb.png" "$(basename "$(dirname "temps/dir one/thumb.png")")_$(basename "temps/dir one/thumb.png") 」
sh -c cp "temps/dir two/thumb.png" "$(basename "$(dirname "temps/dir two/thumb.png")")_$(basename "temps/dir two/thumb.png") 」
答え4
この試み
mkdir /home/user/thumbs
targDir=/home/user/thumbs
cd /home/user/temps
find . -type d |
while IFS="" read -r dir ; do
if [[ -f "${dir}"/thumb.png ]] ; then
echo mv -i "${dir}/thumb.png" "${targDir}/${dir}_thumb.png"
fi
done
編集する
ディレクトリ名にスペース文字が含まれている場合に備えて、引用符を追加しました。
私もこう変えました。ただ実行するコマンドを印刷します。スクリプトの出力を確認して、すべてのファイル/パス名が正しいことを確認してください。実行したいコマンドに問題がないと確信している場合は、そのコマンドを削除してくださいecho
。