Çok sayıda görüntü dosyasını bash ile yeniden adlandırma


16

Yaklaşık olarak yeniden adlandırmam gerekiyor. 70.000 dosya. Örneğin: sb_606_HBO_DPM_0089000ila sb_606_dpm_0089000vb.

Sayı aralığı gider 0089000için 0163022. Bu sadece ismin değişmesi gereken ilk kısmı. tüm dosyalar tek bir dizinde bulunur ve sırayla numaralandırılır (bir görüntü dizisi). Sayılar değişmeden kalmalıdır.

Bunu bash'da denediğimde bana 'Argüman listesi çok uzun' diye grizzles.

Düzenle:

İlk olarak tek bir dosyayı yeniden adlandırmayı denedim mv:

mv sb_606_HBO_DPM_0089000.dpx sb_606_dpm_0089000.dpx

Sonra bir dizi yeniden adlandırmayı denedim (geçen hafta burada dosya yükünü nasıl taşıyacağımı öğrendim, bu yüzden aynı sözdiziminin dosyaları yeniden adlandırmak için işe yarayabileceğini düşündüm ...). Ben düşünüyorum ben aşağıdakileri (veya buna benzer bir şey) çalıştı:

mv sb_606_HBO_DPM_0{089000..163023}.dpx sb_606_dpm_0{089000..163023}.dpx

4
Gözden geçirenler için : Bunun bir kopya olduğunu sanmıyorum; diğer sorudaki CLI yanıtlarının çoğu, kabuğun ARG_MAXsınırıyla çarpışan çok sayıda dosya nedeniyle burada çalışmaz . Bu soru açıkça bir komut satırı çözümü istediğinden, diğer sorudaki gibi (muhtemelen eşit) GUI çözümleri de eşleşmez.
tatlı

1
Bunun bir dupe olduğunu düşünmüyorum çünkü dosyaları yeniden adlandırma konusunda birden fazla soru sormak sorun değil. Lütfen onlara cevap vermeyen jenerik kaynaklara karşı belirli soruları kapatmayalım ...
Zanna

1
@rich Hangi komutu denediğinizi açıkça düzenleyebiliyorsanız, bunun bir dupe olmadığı daha açık olacaktır. (Bu bize bu yaklaşımın farkında olduğunuzu gösterir.) Şerefe.
Sparhawk

2
Zengin, sorunuz bir dupe değil, çünkü belirli bir soru. Bunun için endişelenme. Daha da önemlisi, bir soru çok sayıda yükseltilmiş cevap aldıktan sonra, düzenleme muhtemelen iyi bir fikir değildir çünkü düzenlemeleriniz mevcut cevapları daha az geçerli kılabilir. Şimdi cevabımın neden mv {1..2} {3..4}işe yaramadığını açıklaması gerektiğini hissediyorum , ki bu tamamen farklı bir problem ARG_MAX... Cevap veren herkes muhtemelen aynı hissedecek! Benim açımdan, son düzenlemenizi geri almanızı ve dilerseniz mvaralıklarla ing hakkında yeni bir soru sormanızı dilerim
Zanna

1
@Sparhawk OP, sorunun ilk sürümünden itibaren sorunun argument list too longhata olduğunu açıkça yazdı . Daha fazla açıklamaya gerek yoktur, bu açıkça bir dupe değildir, çünkü ARG_MAX ile başa çıkmak için bir çözüme ihtiyacımız var ve önerilen kopyadaki cevaplar bunu yapmıyor.
terdon

Yanıtlar:


25

Bunun bir yolu , ve seçeneği findile kullanmaktır . Bu bir bağımsız değişken listesi oluşturur, ancak listeyi maksimum bağımsız değişken listesini aşmadan tüm dosyalar üzerinde çalışması için gereken sayıda aramaya böler. Tüm argümanların aynı muamele görmesi uygundur. Olsa da, durum böyle değil .-exec+renamemv

Perl yeniden adlandırmasını yüklemeniz gerekebilir:

sudo apt install rename

Ardından şunları kullanabilirsiniz:

find . -maxdepth 1 -exec rename -n 's/_HBO_DPM_/_dpm_/' {} +

-nDosyaları gerçekten yeniden adlandırmak için test ettikten sonra kaldırın .


11

Üç alternatif önereceğim. Her biri basit bir tek satır komutudur, ancak esas olarak işlenecek dosyaların aynı doğrudan rotadaki diğer dosyalarla karıştırılması durumunda, daha karmaşık durumlar için varyantlar sunacağım.

mmv

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

mmv '*HBO_DPM*' '#1dpm#2'

Bağımsız değişkenlerin dize olarak iletildiğini unutmayın, böylece glob genişlemesi kabukta gerçekleşmez. Komut tam olarak iki bağımsız değişken alır ve ardından dosya sayısı üzerinde sıkı sınırlar olmadan karşılık gelen dosyaları dahili olarak bulur. Ayrıca, yukarıdaki komutun ilk glob ile eşleşen tüm dosyaların yeniden adlandırılacağını varsaydığını unutmayın. Elbette daha spesifik olmakta özgürsünüz:

mmv 'sb_606_HBO_DPM_*' 'sb_606_dpm_#1'

Aynı dizinde istenen sayı aralığının dışında dosyalarınız varsa, bu yanıtta aşağıda verilen sayılar üzerinden döngü ile daha iyi olabilirsiniz. Bununla birlikte, uygun desenlerle bir dizi mmv çağrısı da kullanabilirsiniz:

mmv 'sb_606_HBO_DPM_0089*'       'sb_606_dpm_0089#1'    # 0089000-0089999
mmv 'sb_606_HBO_DPM_009*'        'sb_606_dpm_009#1'     # 0090000-0099999
mmv 'sb_606_HBO_DPM_01[0-5]*'    'sb_606_dpm_01#1#2'    # 0100000-0159999
mmv 'sb_606_HBO_DPM_016[0-2]*'   'sb_606_dpm_016#1#2'   # 0160000-0162999
mmv 'sb_606_HBO_DPM_01630[01]?'  'sb_606_dpm_01630#1#2' # 0163000-0163019
mmv 'sb_606_HBO_DPM_016302[0-2]' 'sb_606_dpm_016302#1'  # 0163020-0163022

sayılar üzerinde döngü

Herhangi bir şey yüklemekten kaçınmak istiyorsanız veya bu aralığın dışındaki eşleşmelerden kaçınarak sayı aralığına göre seçim yapmanız gerekiyorsa ve 74.023 komut çağrısını beklemeye hazırsanız, düz bir bash döngüsü kullanabilirsiniz:

for i in {0089000..0163022}; do mv sb_606_HBO_DPM_$i sb_606_dpm_$i; done

Bu, dizide boşluk olmadığından burada özellikle iyi çalışır. Aksi takdirde, kaynak dosyanın gerçekten var olup olmadığını kontrol etmek isteyebilirsiniz.

for i in {0089000..0163022}; do
  test -e sb_606_HBO_DPM_$i && mv sb_606_HBO_DPM_$i sb_606_dpm_$i
done

for ((i=89000; i<=163022; ++i))Brace genişlemesinin aksine, birkaç yıl önce bazı Bash sürümlerinden bu yana önde gelen sıfırları ele aldığını unutmayın . Aslında istediğim bir değişiklik, bu yüzden bunun için kullanım durumlarını gördüğüme sevindim.

İlave okumalar: Bash bilgi sayfalarında Brace Expansion , özellikle ilgili kısım {x..y[..incr]}.

dosyalar üzerinde döngü

Başka bir seçenek, söz konusu tamsayı aralığında döngü yapmak yerine uygun bir glob üzerinde döngü yapmak olacaktır. Bunun gibi bir şey:

for i in *HBO_DPM*; do mv "$i" "${i/HBO_DPM/dpm}"; done

Yine bu bir mv dosya başına çağrıdır. Ve yine döngü uzun bir öğe listesinin üzerindedir, ancak tüm liste bir alt işleme argüman olarak geçirilmez, ancak dahili olarak bash tarafından işlenir, bu nedenle sınır size sorun yaratmaz.

İlave okumalar: Bash bilgi sayfalarında Shell Parametre Genişletme , ${parameter/pattern/string}diğerleri arasında belgeleme .

Sayı aralığını sağladığınız aralıkla sınırlamak istiyorsanız, bunun için bir kontrol ekleyebilirsiniz:

for i in sb_606_HBO_DPM_+([0-9]); do
  if [[ "${i##*_*(0)}" -ge 89000 ]] && [[ "${i##*_*(0)}" -le 163022 ]]; then
    mv "$i" "${i/HBO_DPM/dpm}"
  fi
done

İşte ${i##pattern}en uzun önek eşleşmesini kaldırır patterndan $i. Bu en uzun önek herhangi bir şey, sonra alt çizgi, sonra sıfır veya daha fazla sıfır olarak tanımlanır. İkincisi, ayarlanan seçeneğe bağlı olarak *(0)genişletilmiş bir glob paterni olarak yazılır . Baştaki sıfırların kaldırılması, sayıyı taban 8 değil, taban 10 olarak ele almak için önemlidir. Döngü bağımsız değişkeninde, aynı başlayan ancak bir ile bitmeyen dosyalarınız olması durumunda, bir veya daha fazla basamağı eşleştiren başka bir genişletilmiş glob'dur. numara.extglob+([0-9])


Teşekkür ederim! Bu bir rüya gibi çalıştı: {0089000..0163022} içindeki i için; mv sb_606_HBO_DPM_ $ i yap sb_606_dpm_ $ i; tamamlandı - Çalışması için dosya adı uzantısını eklemek zorunda kaldım, ancak istediğim şeyi yaptı ve hatta sözdizimini anladım. @MvG
rich

@rich: Mutlu yardımcı olabilirim - siz ve umarım gelecekteki ziyaretçiler de. En faydalı yanıtı kabul etmeyi unutmayın . Daha iyi bir şey gelirse gelecekte bu onay işaretini her zaman değiştirebilirsiniz.
MvG

10

ARG_MAXSınırı aşmanın bir yolu , bash kabuğunun yerleşimini kullanmaktır printf:

printf '%s\0' sb_* | xargs -0 rename -n 's/HBO_DPM/dpm/'

Ör.

rename -n 's/HBO_DPM/dpm/' sb_*
bash: /usr/bin/rename: Argument list too long

fakat

printf '%s\0' sb_* | xargs -0 rename -n 's/HBO_DPM/dpm/'
rename(sb_606_HBO_DPM_0089000, sb_606_dpm_0089000)
.
.
.
rename(sb_606_HBO_DPM_0163022, sb_606_dpm_0163022)

7
find . -type f -exec bash -c 'echo $1 ${1/HBO_DPM/dpm}' _ {} \;
./sb_606_HBO_DPM_0089000 ./sb_606_dpm_0089000

findgeçerli dizinde .tüm dosyalar için -type fve dosyayı yeniden adlandırmak yapmak bulundu $1değiştirilmesi ile HBO_DPMbirlikte dmp birer birer-exec ... \;

yerine echobirlikte mvyeniden adlandırma gerçekleştirmek için.


6

Küçük bir python betiği yazabilirsiniz, şöyle bir şey:

import os
for file in os.listdir("."):
    os.rename(file, file.replace("HBO_DPM", "dpm"))

rename.pyDosyaların bulunduğu klasördeki gibi bir metin dosyası olarak kaydedin, ardından terminal o klasördeki ile:

python rename.py

6

Dosyayı dosya ile yapabilirsiniz (biraz zaman alabilir) ile

sudo apt install util-linux  # if you don't have it already
for i in *; do rename.ul HBO_DPM dpm "$i"; done

renameDiğer cevaplarda kullanılan Perl gibi, rename.ulbir seçenek -nveya --no-acttest için de vardır.


Zanna'nın cevabı hakkındaki yorumunuzu düzenledim, lütfen Zanna'nın cevabını düzenleyin veya yorum yapın.
fosslinux

@ubashu benim cevabım hakkında bir yorum değildi - -ntest etmek ve benim de kullanabileceğimi önermek için kullandığım bayra atıfta bulunmaktı rename.ul.
Zanna

3

Kimsenin en iyi arkadaşımı sedpartiye davet etmediğini görüyorum :). Aşağıdaki fordöngü hedefinize ulaşacaktır:

for i in sb_606_HBO_DPM*; do
  mv "$i" "$(echo $i | sed 's/HBO_DPM/dpm/')";
done

Böyle bir iş için birçok araç var, sizin için en anlaşılır olanı seçin. Bu basit ve bu veya diğer amaçlara uyacak şekilde kolayca değiştirilebilir ...


Kabul edildi, bu özel durumda çok alakalı değil, ancak dosya adlarından herhangi biri yeni satır içeriyorsa bu başarısız olur. Çoğu (tümü?) Diğer yanıtların sağlam olduğundan ve rastgele dosya adlarıyla başa çıkabileceğinden veya yalnızca OP'nin dosya adlandırma şemasında çalışabileceğinden bunu belirtiyorum.
terdon

... yeni satırlar, boşluklar, joker karakterler, ... bunlardan bazıları $ikomut ikamesinde alıntı yapılarak önlenebilir , ancak dosya adında sondaki yeni satırın üstesinden gelmenin kolay bir yolu yoktur.
muru

3

Seçenekler sunduğumuz için işte bir Perl yaklaşımı. cdhedef dizine girin ve çalıştırın:

perl -e 'foreach(glob("sb_*")){rename $_, s/_HBO_DPM_/_dpm_/r}'

açıklama

  • perl -e: tarafından verilen komut dosyasını çalıştırır -e.
  • foreach(glob){}: { }globun her sonucunda ne varsa onu çalıştır .
  • glob("sb_*"): geçerli dizindeki adları kabuk glob ile eşleşen tüm dosyaların ve dizinlerin bir listesini döndürür sb*.
  • rename $_, s/_HBO_DPM_/_dpm_/r: perl büyüsü. $_yinelediğimiz her öğeyi (içinde foreach) tutan özel bir değişkendir . Yani, burada bulunan her dosya olacak. s/_HBO_DPM_/_dpm_/ilk geçtiği yerine _HBO_DPM_ile _dpm_. $_Varsayılan olarak çalışır , bu nedenle her dosya adında çalışır. /rVasıta "hedef dize (dosya adı) bir kopyasına bu değişikliği uygulamak ve modifiye dize döndürür. renameBeklediğiniz yapar: o dosyaları yeniden adlandırır her şey mevcut dosya adını (yeniden adlandırır Yani. $_İle kendisine) _HBO_DPM_ile değiştirildi _dpm_.

Genişletilmiş (ve daha okunabilir bir script) ile aynı şeyi yazabilirsiniz:

#! /usr/bin/env perl
use strict;
use warnings;

foreach my $fileName (glob("sb_*")){
  ## Copy the name to a new variable
  my $newName = $fileName;
  ## change the copy. $newName is now the changed version
  $newName =~ s/_HBO_DPM_/_dpm_/;
  ## rename
  rename $fileName, $newName;
}

1

Öngördüğünüz yeniden adlandırma türüne bağlı olarak, birden çok satır düzenleme ile vidir kullanmak tatmin edici olabilir.
Özel durumunuzda, metin düzenleyicinizdeki tüm satırları seçebilir ve dosya adlarının _ " HBO" bölümünü birkaç tuşa basarak kaldırabilirsiniz .


evet, vi gloable bul ve değiştir var.
Jasen

2
Lütfen cevabınızı uzatabilir ve OP'nin hedefine nasıl ulaşılacağına dair bir örnek verebilir vidirmisiniz?
tatlı
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.