Dosya adlarındaki boşluklar, kısa çizgiler ve alt çizgiler silinsin mi?


10

Bir dizindeki tüm dosyalardan veya seçili dosyalardan boşluk, kısa çizgi ve alt çizgi silmek için iyi bir komut nedir?

Dosya adlarını silmek için Thunar Custom Actions ile aşağıdaki komutu kullanıyorum:

for file in %N; do mv "$file" "$(echo "$file" | tr -s ' ' | tr ' A-Z' '-a-z' | tr -s '-' | tr -c '[:alnum:][:cntrl:].' '-')"; done

Ancak bu komut yalnızca boşlukları tire / kısa çizgi ile değiştirir ve karakterleri küçük harflerle küçültür.

Bir klasördeki binlerce dosya adından boşluk silmek için terminalde aşağıdaki komutu kullandım ve oldukça hızlı çalıştı:

 rename "s/ //g" *

Yine, yalnızca boşlukları siler, tire / tire ve alt çizgi de silmez.

İdeal olarak dosya adlarımda boşluk, kısa çizgi / tire ve alt çizgi istemiyorum. Komutun seçilen dosyalarda Thunar Özel Eylemleri ile kullanılabilmesi harika olurdu.


2
Önerilen çözümlerin birçoğunun sahip olduğu bir problemi, dosyayı göndermeden önce "yeni" adın varlığını düzgün bir şekilde denetlemediğini not ediyorum. Bunu yapmamak birçok sorunun potansiyel kaynağı olabilir.
mdpc

Bunu kontrol etmek için John1024'ün komutunu değiştirmek mümkün mü?
user8547

@ user8547rename -i "s/[-_ ]//g" *
Sparhawk

Teşekkürler Sparhawk. Bu arada, bunu Thunar Özel Eylem olarak kullanmak isteyenler için Thunar'ın komutu şöyledir:% N dosyasında; mv "$ file" yap echo $file | sed -e 's/[ _-]//g'; bitti
user8547

Yanıtlar:


11

Paketle renamebirlikte gelen sürüm perldüzenli ifadeleri destekler:

rename "s/[-_ ]//g" *

Alternatif olarak,

rename -i "s/[-_ ]//g" *

-iBayrak yapmayı daha renameyerine sessizce üzerine yazma, hedef zaten varsa isteyen interaktif modunu kullanın.

Perl'in ismine bazen denir prename.

Perl'in yeniden adlandırılması ve util-linux'un yeniden adlandırılması

Debian benzeri sistemlerde, perl'in yeniden adlandırılması varsayılan olarak görünür ve yukarıdaki komutların çalışması gerekir.

Bazı dağıtımlarda, renameutil-linux yardımcı programı varsayılan değerdir. Bu yardımcı program Perl'lerle tamamen uyumlu değildir rename.

  • Tümü: Öncelikle Perl renameadının mevcut olup olmadığını kontrol edin prename.

  • Debian: Perl'in yeniden adlandırılması varsayılan olmalıdır. Olarak da mevcuttur prename. Bununla renamebirlikte, yürütülebilir dosya /etc/alternativesfarklı bir şeyin kontrolü altındadır ve bu nedenle değiştirilebilir.

  • archlinux: Çalıştır pacman -S perl-renameve komut şu şekilde kullanılabilir perl-rename. Daha kolay bir ad için bir takma ad oluşturun. (Şapka ipucu: KeskiAbs)

  • Mac OSX Bu cevaba göre , renamehomebrew kullanılarak OSX üzerine kurulabilir:

    brew install rename 
  • Doğrudan İndirme: rename Perl Rahipleri'nden de edinilebilir:

     wget 'http://www.perlmonks.org/?displaytype=displaycode;node_id=303814' -O rename

Bunun renameneden bahsettiğine bağlı olduğunu düşünüyorum . Util-linux -2.24.2-1.fc20.x86_64'ten gelen ifade düzenli ifadeleri desteklemez.
Cristian Ciupitu

1
@CristianCiupitu Man sayfasını bulduğunuz yeniden adlandırma sürümü için kontrol ettim. Argümanlara dayanarak rename, OP'nin kullandığı perlsürüm sürüme değil, util-linuxsürüme benziyor .
John1024

Kayıt için, bu util-linux sürümünün kılavuzrename sayfasıdır . Her neyse, bu notun yanı sıra, önemli olan OP'nin cevabını alması (ve benden bir upvote :-D).
Cristian Ciupitu

@CristianCiupitu Bunu bulduğun için teşekkürler. +1 ile size geri dönün.
John1024

1
@ John1024 archlinux, ama nasıl olduğunu öğrendim, sadece git pacman -S perl-renameo zaman sanırım takma ad olabilir.
ChiseledAbs

5

Tüm bu trkomutları sed, örneğin bir ikame komutuyla değiştiririm:

for file in %N; do 
    mv "$file" "$(echo "$file" | sed 's/[ _-]//g')"
done

4

Saymıyorum mv, bunun için gerçekten bir dış işleme ihtiyacınız yok - onları biraz sersemleyebilirsiniz .

ifsqz() ( LC_ALL=C sqz=$1
    isf() { [ -e "$1" ] || [ -L "$1" ] ; }  
    set -- * ; set -f
    for f do isf "$f" || break
    IFS=$sqz; set -- $f; IFS=
    isf "$*" || mv -- "$f" "$*"
    done
)

Yine de, bu mvdosya başına bir çağrı anlamına gelir ve bu yüzden muhtemelen renamedaha iyidir. Bu sadece verilen bir POSIX çalışması gerekir rağmen mviçinde $PATHve bir POSIX kabuk.

Bunun için bir tür çılgın demo hazırladım. Test seti şu şekilde üretilir:

tee - - - - <<CGEN |\
dd cbs=90 conv=unblock |\
sed 'G;$!N'";s/^/touch -- '/;s/$/'/" |sh
$( #BEGIN CGEN
   LC_ALL=C
   i= n='"$((i=((i=i+1)==10||i==39||i==47)>0?(i+1):i))"'
   printf '%b -_   ---___'  $(
   IFS=0; eval \
       printf '"\\\\%04o\\\\%04o "' "$(
       printf "$n"' "$i" '%s $(
       printf %.252d
#END
))"))
CGEN

İlk olarak, yukarıdaki komutun başka yollarla daha kolay elde edilebilen sonuçlar ürettiğini ilk kabul edeceğim. Ancak diğer araçlar muhtemelen ne yapılabileceğini $IFSve biraz (hasta?) Hayal gücü ile gösterilemezdi.

İlk bit oldukça basittir:

  • tee girdisinin 5 kopyasını çıkarır - CGEN

  • dd blok başına 90 bayt satır başına yeni satırlar ile girişini engeller ve ...

  • sedbu blokların \n2'sini iki ewline karakteriyle birleştirir, 'sonuçları tek tırnak içine alır ve touch --her satır döngüsü için dizeyi , ...

  • sh daha sonra kabuk girdisi olarak tüm girdileri yürütür

#CGENBiraz da ... Eh, kısaca ...

  • alt printfbaskı 252 0s

  • Geçen sonraki 252 aldığında ''boş dize argümanlarını ve her içeriklerini yazdırır için $ndize izledi" $i "

  • evalbir sonraki printftepenin argümanlarını, bu yorumun sonuçlarını yazdırmadan önce yorumlar.

  • sonuncusu her printfseferinde bu sekizlik 2 için bayt değerlerini ve ardından -_ ---___her bir çift için dizeyi yazdırır

  • $nartırır bir denkleme başlatıldı $i- bu değerler 10, 39 veya 47 atladığı hariç her değerlendirme için bir kişi tarafından (vardır \newline, 'tek tırnak ve /sırasıyla ASCII ondalık çizgi)

Nihai sonuç, tek tırnak (yalnızca bir deyimden kaçınmak için atlandı sed s///) ve /eğik çizgi hariç 1'den 255'e kadar karakter setimdeki her baytı içeren çok sayıda çirkin dosya adı içeren bir dizindir . Bu dosya adları şöyle görünür:

(set -- *; printf '%s\n\n##############\n\n%s\n' "${9}" "${34}")  | cat -A

   ---___ww -_   ---___xx -_   ---___yy -_   ---___zz -_   ---___{{ -_   ---___|| -_   ---$
$
___}} -_   ---___~~ -_   ---___^?^? -_   ---___M-^@M-^@ -_   ---___M-^AM-^A -_   ---___M-^BM-^B -_   ---___M-^CM-^C$
$
##############$
$
 -_   ---___M-ZM-Z -_   ---___M-[M-[ -_   ---___M-\M-\ -_   ---___M-]M-] -_   ---___M-^M-^ -_   ---___M-_M-_ -_$
$
---___M-`M-` -_   ---___M-aM-a -_   ---___M-bM-b -_   ---___M-cM-c -_   ---___M-dM-d -_   ---___M-eM-e -_   ---___$

Şimdi bu dosyalar hakkında bazı veriler alacağım:

chksqz() ( LC_ALL=C sqz=$1
    set -- * ; set -f ; IFS= ; tc="$*"
    printf '#%s\n' \
        "There are $# files in this test directory." \
        "All filenames combined contain a total of ${#tc} bytes."
    IFS=$sqz ; set -- $* ; IFS= ; sc="$*"  
    printf "%s '$sqz'" \
        "#Of which ${#sc} bytes are not"\
        " and $((${#tc}-${#sc})) bytes are"
    set +f ; unset IFS
    printf ".\n#%s\n#Total:\t%d\n#Other:\t%d\n#'$sqz':\t%d\n" \
        "And to confirm these figures:" \
        $(  printf %s * | wc -c 
            printf %s * | tr -d "$sqz" | wc -c
            printf %s * | tr -dc "$sqz" | wc -c
))
chksqz '_ -'

ÇIKTI

#There are 101 files in this test directory.
#All filenames combined contain a total of 17744 bytes.
#Of which 2692 bytes are not '_ -' and 15052 bytes are '_ -'.
#And to confirm these figures:
#Total: 17744
#Other: 2692
#'_ -': 15052

Tamam. Son olarak, harekete geçmek için:

ifsqz '_ -'
chksqz '_ -'

ÇIKTI

#There are 101 files in this test directory.
#All filenames combined contain a total of 2692 bytes.
#Of which 2692 bytes are not '_ -' and 0 bytes are '_ -'.
#And to confirm these figures:
#Total: 2692
#Other: 2692
#'_ -': 0

Başarı! Kendiniz görebilirsiniz:

ls

????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
???????????????????????????
???????????????????????????
???????????????????????????
????????????????????????????
????????????????????????????
????????????????
??????????????????????
????????????????????????
??????????????????????????
??????????????????????????
??????????????????????????
??????????????????????????
???????????????????????????
???????????????????????????
???????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
??????????????????????????
????????????????????????
????????????????????
??????????????????
????????????????????????????
??
????????????????????????????
??????????????????????????
????????????????????????????
????????????????????????????
????????????????????!!""##
??????????????????!!""##$$
????????????????!!""##$$%%
????????????!!""##$$%%&&((
????????!!""??##$$%%&&(())
$$%%&&(())**??++,,..0011
%%&&(())**++??,,..00112233
&&(())**++,,??..0011223344
))**++,,..??0011223344556
**++,,..00??11223344556677
22334455667788??99::;;<<==>>
445566778899??::;;<<==>>??@@
5566778899::;;??<<==>>??@@AA
6778899::;;<<??==>>??@@AABB
8899::;;<<==??>>??@@AABBCCDD
\\]]^^``aa??bbccddeeffgghh
]]^^``aabbc??cddeeffgghhii
^^``aabbccdd??eeffgghhiijj
??@@AABBCCDDEE??FFGGHHIIJJKK
AABBCCDDEEFF??GGHHIIJJKKLLM
BBCCDDEEFFGG??HHIIJJKKLLMMNN
CCDDEEFFGGHHII??JJKKLLMMNNOO
EEFFGGHHIIJJ??KKLLMMNNOOPPQQ
ffgghhiijjkk??llmmnnooppqqrr
gghhiijjkkllmm??nnooppqqrrss
iijjkkllmmnn??ooppqqrrsstt
jjkkllmmnnoo??ppqqrrssttuuvv
kkllmmnnooppqq??rrssttuuvvww
LLMMNNOOPPQQRR??SSTTUUVVWWXX
MNNOOPPQQRRSS??TTUUVVWWXXYY
OOPPQQRRSSTT??UUVVWWXXYYZZ[[
PPQQRRSSTTUUVV??WWXXYYZZ[[\\
RRSSTTUUVVWW??XXYYZZ[[\\]]
ssttuuvvwwxx??yyzz{{||}}~~??
ttuuvvwwxxyyz??z{{||}}~~????
uuvvwwxxyyzz{{??||}}~~??????
wwxxyyzz{{||??}}~~??????????
xxyyzz{{||}}~~??????????????
YYZZ[[\\]]^^??``aabbccddee
ZZ[[\\]]^^``??aabbccddeeff

2
IFS+ ' printf
In

@ John1024 - gerçekten eğlenceli:set -- 'some arbitrary' args; eval printf '"%s\n"' "$(IFS=0; printf ' "$@" %s' $(printf %025d))"
mikeserv

1
new="$(IFS=" -_"; printf %s $1)"bir alt kabuk çatal (ksh93 hariç) ve satır sonları ile ilgili sorunları var. Başka bir seçenek kullanmaktır IFS=' -_'; set -- $1; IFS=; new="$*"(ve while döngüsünü bir for döngüsü olarak değiştirmek)
Stéphane Chazelas

1
[ -e x ]xvarolmayan veya erişilemeyen bir dosyaya bir sembolik bağlantıysa false değerini döndürür .
Stéphane Chazelas

1
Güzel kabuk Kung-Fu!
karşı

2

perl'iniz varsa, genellikle yeniden adlandırırsınız. yapabilirsin:

> type rename
rename is /usr/bin/rename

ve bu komut dosyasının nasıl yazıldığını gösterin:

> cat /usr/bin/rename | head -n 5 #firt 5 lines for example
#!/usr/bin/perl -w
#
#  This script was developed by Robin Barker (Robin.Barker@npl.co.uk),
#  from Larry Wall's original script eg/rename from the perl source.
#

Bu komut dosyası -i bayrağını desteklemiyor (bu benim sistemimdeki sürüm), ancak belki sizinki destekliyor. Tartışmalar ne olacak? Birincisi, PCRE formatlı düzenli ifadelerdir, filtre gibi çalışır, giriş adını çıkış adına değiştirir. '*' Yıldız işareti ile verdiğiniz giriş adlarının listesi. örneğin:

> cd /tmp
> rename 's/ //g' *

gerçek '*' şu şekilde genişletilebilir:

> rename 's/ //g' file1 file2 file3 othe files found in current directory

Gerçekten büyük sayım dosyalarınız olduğunda, tuzaktasınız. shell, sisteminizi kabul ettiğinden daha uzun bir süre genişletecektir. bul veya xargs kullanarak geçici çözüm yapabilirsiniz. 'find' kullanmak problemdir, çünkü yeniden adlandırma birçok kez dizindeki dosya sayısına eşittir. -r seçeneği ile xargs daha iyi kullanın. bir yeniden adlandırma çağrısı birçok dosyayı değiştirin. Örneğin:

> ls | xargs -r rename 's/ //g'   #thats all, names will be appended at the end of this command.

son sorun ne anlama geliyor:

's/ //g'

bu, adları değiştirmek için normal ifadedir. Önce '/' boşluktur. bu algılanır ve ikinci '/' işaretinden sonra dize ile değiştirilir. Ancak üçüncü '/' ile biten boş dize var, daha sonra boşluk hiçbir şeyle değiştirilmiyor. 'G' seçeneği bu ifadeyi repetatif yapar. ifadesi başından sonuna kadar tüm ad için yürür ve tüm boşlukları algılar.

Peki ya sekme karakteriniz veya başka bir 'beyaz' karakteriniz varsa? Bu '\' için yedek var. başka hangi gereksiz karakterler var? ifadeye eklemeniz yeterlidir. Hepsi parantezle kapanır, örneğin:

's/[\s_-]//g'

hepsi bu. benzerlik görüyor musun Bence insan perlrequick ve erkek perlretut okumak gerekir, bu size (umarım) düzenli ifadenin nasıl çalıştığını açıklar. gerekiyorsa kendi komut dosyanızda rename komutunu kullanabilirsiniz.


1

Aşağıdaki shkabuk döngüsü, varolan dosyaların üzerine yazmamaya dikkat ederek, geçerli dizindeki dosya adlarındaki tüm boşlukları, alt çizgileri ve tireleri kaldıracaktır:

for f in *; do
    test -f "$f" || continue
    nf=$( echo "$f" | tr -d ' _-' )
    ! test -e "$nf" && echo mv "$f" "$nf"
done

Ve için bashve kshmantıkla biraz daha ayrıntılı olmak için:

for f in *; do
    if [[ -f "$f" ]]; then
        nf=$( tr -d ' _-' <<<"$f" )
        if [[ ! -e "$nf" ]]; then
            echo mv "$f" "$nf"
        fi
    fi
done

echoNe yapmak istediğinizi yaptığınızdan emin olduğunuzda kaldırın .

trKomutu (silecektir -dkarakter kümesi verilen) herhangi bir karakter ( ' _-'). Çizginin kümenin en başında veya sonunda olması önemlidir, yoksa bir dizi karakter olarak yorumlanacaktır.

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.