Birden fazla dosyanın uzantısını tekrar tekrar komut satırından nasıl değiştiririm?


Yanıtlar:


85

Taşınabilir bir yol (POSIX uyumlu herhangi bir sistemde çalışacak):

find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;

Bash4'te, özyinelemeli globları almak için globstar kullanabilirsiniz (**):

shopt -s globstar
for file in /the/path/**/*.abc; do
  mv "$file" "${file%.abc}.edefg"
done

renameUbuntu'daki (perl) komutu, globstar veya ile birleştirebileceğiniz perl normal ifade sözdizimini kullanarak dosyaları yeniden adlandırabilir find:

# Using globstar
shopt -s globstar
files=(/the/path/**/*.abc)  

# Best to process the files in chunks to avoid exceeding the maximum argument 
# length. 100 at a time is probably good enough. 
# See http://mywiki.wooledge.org/BashFAQ/095
for ((i = 0; i < ${#files[@]}; i += 100)); do
  rename 's/\.abc$/.edefg/' "${files[@]:i:100}"
done

# Using find:
find /the/path -depth -name "*.abc" -exec rename 's/\.abc$/.edefg/' {} +

Ayrıca bkz. Http://mywiki.wooledge.org/BashFAQ/030


ilki yeni uzantıyı eskisine ekler, yerini almaz ...
user2757729 21:14

3
@ user2757729, onun yerini alıyor. Sonunda olmayan hariç "${1%.abc}"değeri genişler . Shell string manipülasyonları hakkında daha fazla bilgi için Faq 100'e bakınız . $1.abc
geirha

Bunu ~ 70k dosyalık bir dosya yapısında çalıştırdım ... en azından kabuğumda kesinlikle değiştirmedi.
user2757729

1
@ user2757729 Muhtemelen "abc" içinde ${1%.abc}...
bıraktınız

1
Başka birinin alt komutun ilk komutta ne yaptığını merak etmesi durumunda, buna ihtiyaç duyulur, çünkü sh -c ilk argüman $ 0'a atanır ve kalan argümanlar konumsal parametrelere atanır . Yani bu _kukla bir argümandır ve '{}' ilk konum argümanıdır sh -c.
hellobenallan

48

Tüm dosyalar aynı klasördeyse, bu işlem gerekli görevi yerine getirecektir.

rename 's/.abc$/.edefg/' *.abc

Dosyaları sürekli olarak yeniden adlandırmak için şunu kullanın:

find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'

8
Veya rename 's/.abc$/.edefg/' /path/to/root/folder/**/*.abcBash'in modern bir versiyonunda.
Adam Byrtek

Harika * Adam. Klasörlerde * .abc dosyalarının nasıl kullanılacağına dair bir ipucu verdi.
Rafał Cieślak

Harika bir ipucu, teşekkürler! Regex'in sözdiziminin küçük parçası hakkında nereden daha fazla belge bulabilirim? Mesela s, başlangıçtakiler ve orada başka hangi seçenekleri kullanabilirim. Teşekkürler !
Anto

@AdamByrtek Ütopik ile ilgili önerinizle ilgili hata yaptım. ('böyle bir dosya yok' veya bunlardan bazıları.)
Jonathan Y.

14

Özyinelemeli yeniden adlandırmalarla ilgili bir sorun, dosyaları bulmak için hangi yöntemi kullanırsanız kullanın rename, yalnızca dosya adını değil tüm yolu geçmesidir. Bu, iç içe klasörlerdeki karmaşık adların yapılmasını zorlaştırır.

Kullandığım find'ın -execdirbu sorunu çözmek için harekete. -execdirBunun yerine kullanırsanız -exec, belirtilen komut eşleşen dosyayı içeren alt dizinden çalıştırılır. Böylece, tüm yolu geçmek yerine, renamesadece geçer ./filename. Bu regex yazmak için çok daha kolay hale getirir.

find /the/path -type f \
               -name '*.abc' \
               -execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;

Detayda:

  • -type f dizinleri değil yalnızca dosyaları aramak anlamına gelir
  • -name '*.abc' sadece .abc ile biten dosya isimleri ile eşleşir
  • '{}'-execdirbulunan yolu ekleyeceği yeri işaretleyen yer tutucudur . Tek tırnak, dosya adlarını boşluk ve kabuk karakterleriyle işlemesini sağlamak için gereklidir.
  • Ters eğik sonra -typeve -nameBash satır devam karakteri. Bu örneği daha okunaklı hale getirmek için onları kullanıyorum, ancak komutunuzu tek bir satıra yerleştirirseniz bunlara gerek kalmaz.
  • Ancak, -execdirhattın sonundaki ters eğik çizgi gerekir. Tarafından çalıştırılan komutu sonlandıran noktalı virgülden kaçmak için var -execdir. Eğlence!

Regex'in açıklaması:

  • s/ regex'in başlangıcı
  • \.\/öncü ile eşleşir. / that -execdir içeri girer. ve / meta karakterleri (not: bu bölüm sürümünüze bağlı olarak değişir find. user @ apollo adlı kullanıcının yorumuna bakın)
  • (.+)dosya adıyla eşleş. Parantezler daha sonra kullanmak üzere eşleşmeyi yakalar
  • \.abc noktadan kaçmak, abc eşleştirmek
  • $ dizenin sonunda eşleşmeyi tuttur

  • / regex'in "eşleşme" bölümünün sonunu ve "değiştirme" bölümünün başlangıcını işaretler

  • version1_ bu dosyayı her dosya adına ekle

  • $1varolan dosya adına atıfta bulunur, çünkü parantez içinde yakaladık. "Eşleşme" bölümünde birden fazla parantez seti kullanıyorsanız, buraya $ 2, $ 3 vs. kullanarak başvurabilirsiniz.
  • .abcyeni dosya adı .abc ile bitecektir. Burada "değiştir" bölümünde nokta meta karakterinden kaçmaya gerek yok
  • / regex'in sonu

Önce

tree --charset=ascii

|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
    `-- nested_file.abc

Sonra

tree --charset=ascii

|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
    `-- version1_nested_file.abc

İpucu: rename's -n seçeneği kullanışlıdır. Kuru bir işlem yapar ve hangi isimlerin değişeceğini gösterir, ancak herhangi bir değişiklik yapmaz.


Ayrıntılar açıklaması için teşekkürler, ama garip bir şekilde, bunu denediğimde , reçinenin içindeki kısmın atlanabilmesi için önden --execdirgeçemedi . Mayıs, OSX’te değilim çünkü ubuntu değil./\.\/
apollo

5

Başka bir taşınabilir yol:

find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;

4
Ubuntu'ya Sormaya Hoş Geldiniz! Bu değerli bir cevap olsa da, bu komutun nasıl ve neden işe yaradığını açıklamak için genişletmeyi (düzenleyerek) öneririm .
Eliah Kagan


0

Ben de aynen istediğim gibi yaptım ve çalıştım. mvKomutu kullandım . Birden fazla .3gpdosyam vardı ve hepsini yeniden adlandırmak istedim..mp4

İşte bunun için kısa bir oneliner:

for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done

Basitçe geçerli dizini tarar, tüm .3gp dosyalarını alır, sonra (mv kullanarak) yeniden adlandırır ren-name_of_file.mp4


Yani yeniden adlandırır file.3gpiçin file.3gp.mp4çoğu insan ne istediğini olmayabilir, hangi.
muru

@muru ama ilke hala var. Herhangi bir uzantıyı seçip yeniden adlandırmak için hedef uzantıyı belirtmeniz yeterlidir . .3gpVeya .mp4burada örnek amacıyla sadece idi.
KhoPhi

Sözdizimi tercih edilir, tek yönlü ve anlaşılması kolaydır. Ancak, basename "$i" .mp4"ren- $ i.mp4" yerine önceki uzantıyı kaldırmak için kullanırdım.
TaoPR

Doğru. İyi bir nokta.
KhoPhi

0

Bunu başarmanın kolay bir yolunu buldum. Birçok dosyanın uzantısını jpg'den pdf'ye değiştirmek için, aşağıdakileri kullanın:

for file in /path/to; do mv $file $(basename -s jpg $file)pdf ; done

0

Bana kalırsa doğru mmv komutunu gelen aynı adlı pakette :

mmv ';*.abc' '#1#2.edefg'

;Maçları sıfır veya daha fazla */ve karşılık gelen #1replasmanı. Karşılık *gelir #2. Özyinelemeli olmayan sürüm

mmv '*.abc' '#1.edefg'

0

Dosya ve klasörleri yeniden adlandır find -execdir | rename

Hem dosyaları hem de dizinleri sadece bir sonek ile değil, yeniden adlandıracaksanız, bu iyi bir kalıptır:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find . -depth -execdir rename 's/findme/replaceme/' '{}' \;

Awesome -execdirseçeneği cd, renamekomutu çalıştırmadan önce dizine a yapar -exec.

-depth eksik ebeveyn dizinleri ile ilgili olası sorunları önlemek için yeniden adlandırma işleminin önce çocuklar üzerinde, sonra ebeveynler üzerinde yapıldığından emin olun.

-execdir Yeniden adlandırma, taban adı olmayan girdi yollarıyla iyi çalışmadığı için gereklidir, örneğin aşağıdakiler başarısız olur:

rename 's/findme/replaceme/g' acc/acc

Bilgisayar PATHkorsanlığı gereklidir, çünkü -execdirçok can sıkıcı bir dezavantajı vardır: findson derece tartışılır ve ortam değişkeninizde -execdirgöreceli yollarınız varsa PATH, örneğin ./node_modules/.bin:

find: './node_modules/.bin' göreceli yolu, find -execdir eylemiyle birlikte güvensiz olan PATH ortam değişkenine dahil edilir. Lütfen bu girişi $ PATH içinden kaldırın

Ayrıca bakınız: Neden '-execdir' eylemini kullanmak PATH'taki dizin için güvensiz?

-execdirPOSIX için bir GNU bulma uzantısıdır . renamePerl tabanlı ve renamepaketten geliyor . Ubuntu 18.10'da test edilmiştir.

Lookahead geçici çözümünü yeniden adlandır

Girdi yollarınız gelmiyorsa findveya göreceli yol sıkıntısından yeterince kurtulduysanız, dizinleri aşağıdaki gibi güvenli bir şekilde yeniden adlandırmak için bazı Perl görünümlerini kullanabiliriz:

git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'

Ben için uygun bir analog bulamadık -execdirile xargs: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686

sort -rUzun yollar aynı öneki ile kısa olanlar peşine beri dosyaları kendi dizinleri sonra gelmek sağlamak için gereklidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.