Bir bash betiğinde dosya adının uzantısını nasıl kontrol edebilirim?


170

Ben her gece bash dilinde bir senaryo yazıyorum.
Küçük bir engel dışında her şey iyi ve züppe:


#!/bin/bash

for file in "$PATH_TO_SOMEWHERE"; do
      if [ -d $file ]
      then
              # do something directory-ish
      else
              if [ "$file" == "*.txt" ]       #  this is the snag
              then
                     # do something txt-ish
              fi
      fi
done;

Benim sorunum dosya uzantısını belirlemek ve daha sonra buna göre hareket etmektir. Sorunun bir txt dosyası için test if-ifadesinde olduğunu biliyorum.

Bir dosyanın .txt sonekine sahip olup olmadığını nasıl belirleyebilirim?


Adında boşluk olan bir dosyanız varsa bu işlem bozulur.
jfg956

Paul'ün cevabına ek olarak, $(dirname $PATH_TO_SOMEWHERE)ve $(basename $PATH_TO_SOMEWHERE)klasör ve dizine bölmek ve dizin-ish ve dosya-ish bir şey yapmak için kullanabilirsiniz
McPeppr

Yanıtlar:


250

Sanırım "$ dosyasının son dört karakteri eşit .txtmi?" Öyleyse, aşağıdakileri kullanabilirsiniz:

if [ ${file: -4} == ".txt" ]

Arasındaki boşluk o Not file:ve -4değiştirici araçlar farklı bir şey: - '' gibi gereklidir.


1
bu amaçla, windows.com'da da command.com'u command.txt olarak yeniden adlandırabilirsiniz.
hometoast

9
Bir eşitsizlik belirtmek istiyorsanız, fazladan köşeli ayraç eklemeyi unutmayın: eğer [[$ {file: -4}! = ".Txt"]]
Ram Rajamony

4
@RamRajamony Eşitsizliği test ederken [[kullanmak neden gereklidir?
PesaThe

Kolondan sonraki boşluğun önemli olduğunu belirtmek istedim. ${var:-4}ile aynı değildir ${var: -4}; ilk (boşluk olmadan) var ayarlanmamışsa '-4' olarak genişler, ikincisi (boşluk ile) var.
pbatey

1
Bash içinde, ilk değişkenin etrafına tırnak koymazsanız bu bir "[: ==: tekli operatör bekleniyordu" hatası üretecektir. Bunun if [ "${file: -4}" == ".txt" ]yerine.
Giles B

264

Yapmak

if [ "$file" == "*.txt" ]

bunun gibi:

if [[ $file == *.txt ]]

Yani, çift parantez ve tırnak yok.

Sağ tarafı ==bir kabuk desenidir. Normal bir ifadeye ihtiyacınız varsa =~o zaman kullanın .


15
Bunu bilmiyordum. == veya! = 'Nin sağ tarafının kabuk deseni olarak genişletildiği özel bir durum gibi görünüyor. Şahsen bunun cevabımdan daha net olduğunu düşünüyorum.
Paul Stephenson

20
Bash konusunda yeniyim ve bunu çok koşullu bir ififadede nasıl kullanacağımı anlamak biraz zaman aldı . Birisine yardım etmesi durumunda burada paylaşıyorum. if [[ ( $file == *.csv ) || ( $file == *.png ) ]]
joelostblom

6
@cheflo, genel olarak birden fazla koşul için iyidir. Bu özel durumda, kullanabilirsiniz if [[ $file =~ .*\.(csv|png) ]]. Daha kısa, daha net, ek uzantılar eklemek daha kolay ve kolayca yapılandırılabilir hale getirilebilir ("değişken" csv | png "koyarak).
jox

4
Dosyanın etrafına çift tırnak işareti koyabilirsiniz. if [[ "$file" == *.txt ]]Dosyanın adında boşluk varsa, çift tırnak işareti gerekir.
shawnhcorey

Bu cevabı kabul edilen cevap yerine kullanmalı mıyım?
Freedo

26

Unix sisteminde, .txt dosyasının gerçekten bir metin dosyası olduğundan emin olamazsınız. En iyi seçiminiz "file" kullanmaktır. Belki şunu kullanmayı deneyin:

file -ib "$file"

Daha sonra, MIME'nin "metin", "uygulama" vb.


2
Gibi file -i...mim kodlamasını içeren, kullanabilirsinizfile --mime-type -b ...
Wilf

24

Uzantılara güvenmek yerine dosya hakkında gerçekten bilgi edinmek istiyorsanız "dosya" komutunu kullanabilirsiniz.

Uzantıyı kullanmaktan çekiniyorsanız grep'i eşleşip eşleşmediğini görebilirsiniz.


evet emrin farkındayım file. Aslında söz konusu komutun çıktısına göre eşleştirmeyi denemiştim ... ama bu if-ifadelerinde korkunç bir şekilde başarısızım.

17

Ayrıca şunları da yapabilirsiniz:

   if [ "${FILE##*.}" = "txt" ]; then
       # operation for txt files here
   fi

11
case $FILE in *.txt ) ... ;; esacdaha sağlam ve deyimsel görünüyordu.
tripleee

11

'File' dosyasına benzer şekilde, dosya uzantısı ne olursa olsun biraz daha basit olan 'mimetype -b' kullanın.

if [ $(mimetype -b "$MyFile") == "text/plain" ]
then
  echo "this is a text file"
fi

Düzenleme: mimetype kullanılamıyorsa sisteminize libfile-mimeinfo-perl yüklemeniz gerekebilir


1
'Mimetype' betiğinin tüm sistemlerde bulunmadığını açıkça belirtmelisiniz.
gilbertpilz

Tamamlandı, libfile-mimeinfo-perl eklendi
dargaud

5

Linux'ta bir dosya adında bulunan uzantıyı nasıl alacağınıza dair doğru cevap:

${filename##*\.} 

Bir dizindeki tüm dosya uzantılarını yazdırma örneği

for fname in $(find . -maxdepth 1 -type f) # only regular file in the current dir
    do  echo ${fname##*\.} #print extensions 
done

Yanıtınız çift ters eğik çizgi kullanıyor ancak örneğiniz yalnızca tek bir ters eğik çizgi kullanıyor. Örneğin doğru, cevabınız doğru değil.
gilbertpilz

3

Bir dosya türüne bakan bir bash betiği yazdım, sonra bir konuma kopyaladım, çevrimiçi olarak izlediğim videolara bakmak için firefox önbelleğimden kullanıyorum:

#!/bin/bash
# flvcache script

CACHE=~/.mozilla/firefox/xxxxxxxx.default/Cache
OUTPUTDIR=~/Videos/flvs
MINFILESIZE=2M

for f in `find $CACHE -size +$MINFILESIZE`
do
    a=$(file $f | cut -f2 -d ' ')
    o=$(basename $f)
    if [ "$a" = "Macromedia" ]
        then
            cp "$f" "$OUTPUTDIR/$o"
    fi
done

nautilus  "$OUTPUTDIR"&

Burada sunulanlara benzer fikirler kullanır, umarım bu birileri için yararlıdır.


2

Sanırım böyle '$PATH_TO_SOMEWHERE'bir şey '<directory>/*'.

Bu durumda, kodu şöyle değiştiririm:

find <directory> -maxdepth 1 -type d -exec ... \;
find <directory> -maxdepth 1 -type f -name "*.txt" -exec ... \;

Dizin ve metin dosyası adlarıyla daha karmaşık bir şey yapmak istiyorsanız, şunları yapabilirsiniz:

find <directory> -maxdepth 1 -type d | while read dir; do echo $dir; ...; done
find <directory> -maxdepth 1 -type f -name "*.txt" | while read txtfile; do echo $txtfile; ...; done

Dosya adlarınızda boşluk varsa, şunları yapabilirsiniz:

find <directory> -maxdepth 1 -type d | xargs ...
find <directory> -maxdepth 1 -type f -name "*.txt" | xargs ...

Bunlar kabukta 'döngüler' yapmanın harika örnekleridir. Açık forve whiledöngüler, döngü gövdesinin daha karmaşık olması gerektiğinde ayrılmalıdı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.