Objektif
Ubah nama file ini:
- F00001-0708-RG-biasliuyda
- F00001-0708-CS-akgdlaul
- F00001-0708-VF-hioulgigl
ke nama file ini:
- F0001-0708-RG-biasliuyda
- F0001-0708-CS-akgdlaul
- F0001-0708-VF-hioulgigl
Kode Shell
Untuk mengetes:
ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/'
Untuk melakukan:
ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/' | sh
Pertanyaan saya
Saya tidak mengerti kode sed. Saya mengerti apa perintah substitusi
$ sed 's/something/mv'
cara. Dan saya agak memahami ekspresi reguler. Tapi saya tidak mengerti apa yang terjadi di sini:
\(.\).\(.*\)
atau di sini:
& \1\2/
Yang pertama, bagi saya, sepertinya itu berarti: "satu karakter, diikuti oleh satu karakter, diikuti dengan urutan panjang apa pun dari satu karakter" - tapi pasti ada yang lebih dari itu. Sejauh bagian terakhir:
& \1\2/
Saya tidak punya ide.
bash
shell
sed
file-rename
Daniel Underwood
sumber
sumber
Jawaban:
Pertama, saya harus mengatakan bahwa cara termudah untuk melakukan ini adalah dengan menggunakan perintah prename atau ganti nama.
Di Ubuntu, OSX (paket Homebrew
rename
, paket MacPortsp5-file-rename
), atau sistem lain dengan perl rename (nama awal):atau pada sistem dengan ganti nama dari util-linux-ng, seperti RHEL:
Itu jauh lebih bisa dimengerti daripada perintah sed yang setara.
Tetapi untuk memahami perintah sed, halaman manual sed sangat membantu. Jika Anda menjalankan man sed dan mencari & (menggunakan / perintah untuk mencari), Anda akan menemukan itu adalah karakter khusus di s / foo / bar / replacements.
s/regexp/replacement/ Attempt to match regexp against the pattern space. If success‐ ful, replace that portion matched with replacement. The replacement may contain the special character & to refer to that portion of the pattern space which matched, and the special escapes \1 through \9 to refer to the corresponding matching sub-expressions in the regexp.
Oleh karena itu,
\(.\)
cocokkan karakter pertama, yang dapat dirujuk oleh\1
. Kemudian.
cocok dengan karakter berikutnya, yang selalu 0. Kemudian\(.*\)
cocok dengan sisa nama file, yang dapat direferensikan oleh\2
.String pengganti menyatukan semuanya menggunakan
&
(nama file asli) dan\1\2
yang merupakan setiap bagian dari nama file kecuali karakter ke-2, yang merupakan 0.Ini adalah cara yang cukup samar untuk melakukan ini, IMHO. Jika karena alasan tertentu perintah ganti nama tidak tersedia dan Anda ingin menggunakan sed untuk mengganti nama (atau mungkin Anda melakukan sesuatu yang terlalu rumit untuk diganti nama?), Menjadi lebih eksplisit dalam regex Anda akan membuatnya lebih mudah dibaca. Mungkin sesuatu seperti:
ls F00001-0708-*|sed 's/F0000\(.*\)/mv & F000\1/' | sh
Mampu melihat apa yang sebenarnya berubah di s / search / replacement / membuatnya lebih mudah dibaca. Juga tidak akan terus menyedot karakter dari nama file Anda jika Anda tidak sengaja menjalankannya dua kali atau sesuatu.
sumber
rename
sendiri adalah tautan yang "diubah namanya" . ierename
telah "diganti namanya" dariprename
.. misalnya, di Ubuntu:readlink -f $(which rename)
output/usr/bin/prename
... Yangrename
disebutkan oleh David adalah program yang sama sekali berbeda.sh
? ini berpotensi berbahaya karena kode arbitrer dapat dieksekusi (Anda memperlakukan data sebagai kode).Anda sudah memiliki penjelasan sed, sekarang Anda dapat menggunakan shell saja, tidak perlu perintah eksternal
for file in F0000* do echo mv "$file" "${file/#F0000/F000}" # ${file/#F0000/F000} means replace the pattern that starts at beginning of string done
sumber
Saya menulis posting kecil dengan contoh tentang penggantian nama batch menggunakan
sed
beberapa tahun yang lalu:http://www.guyrutenberg.com/2009/01/12/batch-renaming-using-sed/
Sebagai contoh:
for i in *; do mv "$i" "`echo $i | sed "s/regex/replace_text/"`"; done
Jika regex berisi grup (mis.
\(subregex\
) Maka Anda dapat menggunakannya dalam teks pengganti sebagai\1\
,\2
dll.sumber
Cara termudah adalah:
for i in F00001*; do mv "$i" "${i/F00001/F0001}"; done
atau, secara portabel,
for i in F00001*; do mv "$i" "F0001${i#F00001}"; done
Ini menggantikan
F00001
awalan di nama file denganF0001
. kredit untuk mahesh di sini: http://www.debian-administration.org/articles/150sumber
mv "$i" "${i/F00001/F0001}"
. Tapi +1The
sed
perintahsarana untuk menggantikan:
dengan:
seperti
sed
perintah biasa . Namun, tanda kurung&
dan\n
penanda mengubahnya sedikit.String pencarian cocok (dan mengingat sebagai pola 1) karakter tunggal di awal, diikuti oleh satu karakter, diikuti oleh sisa string (diingat sebagai pola 2).
Dalam string pengganti, Anda dapat merujuk ke pola yang cocok ini untuk menggunakannya sebagai bagian dari pengganti. Anda juga bisa merujuk ke seluruh bagian yang cocok sebagai
&
.Jadi apa yang dilakukan
sed
perintah itu adalah membuatmv
perintah berdasarkan file asli (untuk sumber) dan karakter 1 dan 3 dan seterusnya, secara efektif menghapus karakter 2 (untuk tujuan). Ini akan memberi Anda serangkaian garis di sepanjang format berikut:dan seterusnya.
sumber
ls | sed "s/\(.\).\(.*\)/mv & \1\2/" | bash
ls
, menyalurkan,sed
dan kemudian menyalurkan melalui cangkang! itu tunduk pada eksekusi kode arbitrer dengan nama file palsu. Masalahnya adalah bahwa data harus diperlakukan sebagai data, dan di sini biasanya diserialkan menjadi kode tanpa tindakan pencegahan apa pun. Saya berharap paxdiablo dapat menghapus jawaban ini karena ini benar-benar tidak menunjukkan praktik yang baik. (Saya tersandung pada pertanyaan ini karena seorang pemula secara acak menyalurkan| sh
perintah yang tidak berhasil dan setelah melihat pertanyaan ini dan jawabannya mengira itu akan bekerja lebih baik — saya ngeri!):)
.Kata backslash-paren berarti, "sambil mencocokkan pola, pegang benda yang cocok di sini." Nanti, di sisi teks pengganti, Anda bisa mendapatkan kembali fragmen yang diingat dengan "\ 1" (blok tanda kurung pertama), "\ 2" (blok kedua), dan seterusnya.
sumber
Jika semua yang Anda lakukan sebenarnya adalah menghapus karakter kedua, apa pun itu, Anda dapat melakukan ini:
tetapi perintah Anda adalah membuat
mv
perintah dan mengirimkannya ke shell untuk dieksekusi.Ini tidak lebih dapat dibaca dari versi Anda:
find -type f | sed -n 'h;s/.//4;x;s/^/mv /;G;s/\n/ /g;p' | sh
Karakter keempat dihapus karena
find
mempersiapkan setiap nama file dengan "./".sumber
| sh
perintah yang tidak berfungsi, dengan harapan itu akan berhasil lebih baik. Mengerikan! (dan selain itu, itu bukan praktik yang baik). Saya harap Anda mengerti!Menggunakan perl rename ( harus ada di toolbox):
rename -n 's/0000/000/' F0000*
Lepaskan
-n
sakelar ketika output terlihat bagus untuk mengganti nama secara nyata.Ada alat lain dengan nama yang sama yang mungkin dapat atau tidak dapat melakukan ini, jadi berhati-hatilah.
Perintah ganti nama yang merupakan bagian dari
util-linux
paket, tidak akan.Jika Anda menjalankan perintah berikut (
GNU
)dan Anda lihat
perlexpr
, ini sepertinya alat yang tepat.Jika belum, jadikan default (biasanya sudah case) on
Debian
dan turunannya sepertiUbuntu
:$ sudo apt install rename $ sudo update-alternatives --set rename /usr/bin/file-rename
Untuk archlinux:
Untuk distro keluarga RedHat:
Paket 'prename' ada di repositori EPEL .
Untuk Gentoo:
Untuk * BSD:
atau
p5-File-Rename
Untuk pengguna Mac:
Jika Anda tidak memiliki perintah ini dengan distro lain, cari manajer paket Anda untuk menginstalnya atau lakukan secara manual :
Versi mandiri lama dapat ditemukan di sini
ganti nama pria
Alat ini aslinya ditulis oleh Larry Wall, ayah Perl.
sumber
Tanda kurung menangkap string tertentu untuk digunakan oleh angka yang miring terbalik.
sumber
ls F00001-0708-*|sed 's|^F0000\(.*\)|mv & F000\1|' | bash
sumber
Inilah yang akan saya lakukan:
for file in *.[Jj][Pp][Gg] ;do echo mv -vi \"$file\" `jhead $file| grep Date| cut -b 16-| sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ; done
Kemudian jika itu terlihat oke, tambahkan
| sh
ke bagian akhir. Begitu:for file in *.[Jj][Pp][Gg] ;do echo mv -vi \"$file\" `jhead $file| grep Date| cut -b 16-| sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ; done | sh
sumber
Beberapa contoh yang berhasil untuk saya:
$ tree -L 1 -F . . ├── A.Show.2020.1400MB.txt └── Some Show S01E01 the Loreming.txt 0 directories, 2 files ## remove "1400MB" (I: ignore case) ... $ for f in *; do mv 2>/dev/null -v "$f" "`echo $f | sed -r 's/.[0-9]{1,}mb//I'`"; done; renamed 'A.Show.2020.1400MB.txt' -> 'A.Show.2020.txt' ## change "S01E01 the" to "S01E01 The" ## \U& : change (here: regex-selected) text to uppercase; ## note also: no need here for `\1` in that regex expression $ for f in *; do mv 2>/dev/null "$f" "`echo $f | sed -r "s/([0-9] [a-z])/\U&/"`"; done $ tree -L 1 -F . . ├── A.Show.2020.txt └── Some Show S01E01 The Loreming.txt 0 directories, 2 files $
2>/dev/null
menekan keluaran asing (peringatan ...)referensi [utas ini]: https://stackoverflow.com/a/2372808/1904943
ubah kasus: https://www.networkworld.com/article/3529409/converting-between-uppercase-and-lowercase-on-the-linux-command-line.html
sumber
for i in *; do mv $i $(echo $i|sed 's/AAA/BBB/'); done
sumber