Bagaimana saya bisa meratakan direktori dalam format berikut?
Sebelum: ./aaa/bbb/ccc.png
Setelah: ./aaa-bbb-ccc.png
./foo/bar/baz.pngdan ./foo-bar-baz.pngkeduanya ada. Saya berasumsi Anda tidak ingin mengganti yang terakhir dengan yang pertama?
Bagaimana saya bisa meratakan direktori dalam format berikut?
Sebelum: ./aaa/bbb/ccc.png
Setelah: ./aaa-bbb-ccc.png
./foo/bar/baz.pngdan ./foo-bar-baz.pngkeduanya ada. Saya berasumsi Anda tidak ingin mengganti yang terakhir dengan yang pertama?
Jawaban:
Peringatan: Saya mengetik sebagian besar perintah ini langsung di browser saya. Lektor peringatan.
Dengan zsh dan zmv :
zmv -o -i -Qn '(**/)(*)(D)' '${1//\//-}$2'
Penjelasan: Pola ini **/*cocok dengan semua file di subdirektori dari direktori saat ini, secara rekursif (tidak cocok dengan file di direktori saat ini, tetapi ini tidak perlu diganti namanya). Dua pasang kurung pertama adalah grup yang dapat disebut sebagai $1dan $2dalam teks pengganti. Pasangan terakhir kurung menambahkan D kualifikasi glob sehingga file dot tidak dihilangkan. -o -iartinya meneruskan -iopsi ke mvsehingga Anda diminta jika file yang ada akan ditimpa.
Dengan hanya alat POSIX:
find . -depth -exec sh -c '
for source; do
case $source in ./*/*)
target="$(printf %sz "${source#./}" | tr / -)";
mv -i -- "$source" "${target%z}";;
esac
done
' _ {} +
Penjelasan: casepernyataan menghilangkan direktori saat ini dan subdirektori tingkat atas dari direktori saat ini. targetberisi nama file sumber ( $0) dengan ./strip utama dan semua garis miring diganti dengan tanda hubung, ditambah final z. Final zada di sana dalam kasus nama file berakhir dengan baris baru: jika tidak, substitusi perintah akan menghapusnya.
Jika Anda findtidak mendukung -exec … +(OpenBSD, saya melihat Anda):
find . -depth -exec sh -c '
case $0 in ./*/*)
target="$(printf %sz "${0#./}" | tr / -)";
mv -i -- "$0" "${target%z}";;
esac
' {} \;
Dengan bash (atau ksh93), Anda tidak perlu memanggil perintah eksternal untuk mengganti garis miring dengan tanda hubung, Anda dapat menggunakan ekspansi parameter ksh93 dengan konstruksi penggantian string ${VAR//STRING/REPLACEMENT}:
find . -depth -exec bash -c '
for source; do
case $source in ./*/*)
source=${source#./}
target="${source//\//-}";
mv -i -- "$source" "$target";;
esac
done
' _ {} +
for sourceContoh - contoh melewatkan file / dir pertama yang disajikan ... Saya akhirnya menemukan mengapa Anda (biasanya) telah menggunakan _sebagai $0:) ... dan terima kasih atas jawaban yang bagus. Saya belajar banyak dari mereka.
Meskipun sudah ada jawaban bagus di sini, saya menemukan ini lebih intuitif, di dalam bash:
find aaa -type f -exec sh -c 'new=$(echo "{}" | tr "/" "-" | tr " " "_"); mv "{}" "$new"' \;
Di mana aaadirektori Anda saat ini. File-file yang dikandungnya akan dipindahkan ke direktori saat ini (hanya menyisakan direktori kosong di aaa). Kedua panggilan untuk trmenangani direktori dan ruang (tanpa logika untuk tebas lolos - latihan untuk pembaca).
Saya menganggap ini lebih intuitif dan relatif mudah untuk di-tweak. Yaitu saya bisa mengubah findparameter jika mengatakan saya hanya ingin mencari file .png. Saya dapat mengubah trpanggilan, atau menambahkan lebih banyak sesuai kebutuhan. Dan saya dapat menambahkan echosebelumnya mvjika saya ingin memeriksa secara visual bahwa itu akan melakukan hal yang benar (kemudian ulangi tanpa tambahan echohanya jika semuanya terlihat benar:
find aaa -name \*.png -exec sh -c 'new=$(echo "{}" | tr "/" "-" | tr " " "_"); echo mv "{}" "$new"' \;
Perhatikan juga saya menggunakan find aaa... dan tidak find .... atau find aaa/... karena dua yang terakhir akan meninggalkan artefak lucu di nama file terakhir.
find . -mindepth 2 -type f -name '*' |
perl -l000ne 'print $_; s/\//-/g; s/^\.-/.\// and print' |
xargs -0n2 mv
Catatan: ini tidak akan berfungsi untuk nama file yang mengandung \n.
Ini, tentu saja hanya memindahkan ffile jenis ...
Satu-satunya bentrokan nama akan dari file yang sudah ada di pwd
Diuji dengan bagian dasar ini
rm -fr junk
rm -f junk*hello*
mkdir -p junk/junkier/junkiest
touch 'hello hello'
touch 'junk/hello hello'
touch 'junk/junkier/hello hello'
touch 'junk/junkier/junkiest/hello hello'
Yang menghasilkan
./hello hello
./junk-hello hello
./junk-junkier-hello hello
./junk-junkier-junkiest-hello hello
Ini adalah lsversi .. selamat datang komentar. Ini berfungsi untuk nama file yang aneh seperti ini
"j1ळ\n\001\n/j2/j3/j4/\nh h\n", tetapi saya benar-benar tertarik untuk mengetahui adanya jebakan. Ini lebih merupakan latihan dalam "dapatkah difitnah lsbenar-benar melakukannya (dengan kuat)?"
ls -AbQR1p * | # paths in "quoted" \escaped format
sed -n '/":$/,${/.[^/]$/p}' | # skip files in pwd, blank and dir/ lines
{ bwd="$PWD"; while read -n1; # save base dir strip leading "quote
read -r p; do # read path
printf -vs "${p%\"*}" # strip trailing quote"(:)
[[ $p == *: ]] && { # this is a directory
cd "$bwd/$s" # change into new directory
rnp="${s//\//-}"- # relative name prefix
} || mv "$s" "$bwd/$rnp$s"
done; }
Cukup pipa nama file + path ke trperintah.tr <replace> <with>
for FILE in `find aaa -name "*.png"`
do
NEWFILE=`echo $FILE | tr '/' '-'`
cp -v $FILE $NEWFILE
done
cpsaluran akan cp -v "$FILE" "$NEWFILE"membantu? (Juga, Anda seharusnya tidak hanya mengasumsikan file png.)
cpbaris tidak cukup. Seluruh pendekatan findoutput parsing dengan forloop cacat. Satu-satunya cara aman untuk digunakan findadalah dengan -exec, atau -print0jika tersedia (kurang portabel dari -exec). Saya akan menyarankan alternatif yang lebih kuat tetapi pertanyaan Anda saat ini tidak ditentukan.
Aman untuk spasi dalam nama file:
#!/bin/bash
/bin/find $PWD -type f | while read FILE
do
_new="${FILE//\//-}"
_new="${_new:1}"
#echo $FILE
#echo $_new
/bin/mv "$FILE" "$_new"
done
Berlari dengan saya cpalih - alih mvkarena alasan yang jelas, tetapi harus menghasilkan hal yang sama.
type find-> find is /usr/bin/finddi mesin saya. Menggunakan PATHsebagai nama variabel dalam sebuah skrip adalah ide yang buruk. Juga, skrip Anda manglesi nama file dengan spasi atau garis miring terbalik, karena Anda menyalahgunakan readperintah (cari situs ini IFS read -r).
find is hashed (/bin/find), relevan bagaimana? Distro yang berbeda berbeda?
PATHvariabel lingkungan, yang merupakan sesuatu yang digunakan oleh setiap sistem Unix. Jika Anda menulis /bin/findmaka skrip Anda benar-benar rusak pada setiap sistem (Gilles, milikku, dan mungkin OP) yang tidak memiliki /bin/find(misalnya b / c itu ada di /usr/bin/find). Inti dari PATHvariabel lingkungan adalah menjadikan ini bukan masalah.
$(pwd)sudah tersedia dalam variabel: $PWD. Tetapi Anda tidak boleh menggunakan jalur absolut di sini: jika skrip Anda dipanggil dari, katakanlah /home/tim, ia mencoba mengubah namanya /home/tim/some/pathmenjadi /home-tim-some-path.