Bagaimana cara memeriksa ekstensi nama file dalam skrip bash?

170

Saya menulis skrip membangun malam di bash.
Semuanya baik-baik saja dan keren kecuali untuk satu hambatan kecil:


#!/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;

Masalah saya adalah menentukan ekstensi file dan kemudian bertindak sesuai. Saya tahu masalahnya ada di pernyataan if, menguji file txt.

Bagaimana saya bisa menentukan apakah suatu file memiliki akhiran .txt?

Anthon
sumber
Ini akan rusak jika Anda memiliki file dengan spasi di namanya.
jfg956
Selain jawaban Paul, Anda dapat menggunakan $(dirname $PATH_TO_SOMEWHERE)dan $(basename $PATH_TO_SOMEWHERE)memecah menjadi folder dan direktori dan melakukan sesuatu direktori-ish dan file-ish
McPeppr

Jawaban:

248

Saya pikir Anda ingin mengatakan "Apakah empat karakter terakhir dari $ file sama dengan .txt?" Jika demikian, Anda dapat menggunakan yang berikut ini:

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

Perhatikan bahwa ruang antara file:dan -4diperlukan, karena pengubah ': -' berarti sesuatu yang berbeda.

Paul Stephenson
sumber
1
untuk itu, Anda dapat mengubah nama command.com menjadi command.txt di mesin windows juga.
Hometoast
9
Jika Anda ingin menentukan ketidaksetaraan, ingatlah untuk memasukkan tanda kurung tambahan: if [[$ {file: -4}! = ".Txt"]]
Ram Rajamony
4
@RamRajamony Mengapa perlu menggunakan [[saat menguji ketimpangan?
PesaThe
Saya ingin menunjukkan bahwa ruang setelah usus besar itu penting. ${var:-4}tidak sama dengan ${var: -4}; yang pertama (tanpa spasi) akan berkembang sebagai '-4' jika var tidak disetel yang kedua (dengan spasi) mengembalikan 4 karakter terakhir dari var.
pbatey
1
Dalam bash, ini akan menghasilkan kesalahan "[: ==: operator yang tidak diharapkan" kecuali Anda memberi tanda kutip di sekitar variabel pertama. Jadi if [ "${file: -4}" == ".txt" ]sebagai gantinya.
Giles B
264

Membuat

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

seperti ini:

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

Yaitu, kurung ganda dan tidak ada tanda kutip.

Sisi kanan ==adalah pola shell. Jika Anda memerlukan ekspresi reguler, gunakan =~kemudian.


sumber
15
Saya tidak tahu tentang ini. Tampaknya menjadi kasus khusus bahwa sisi kanan == atau! = Diperluas sebagai pola shell. Secara pribadi saya pikir ini lebih jelas daripada jawaban saya.
Paul Stephenson
20
Saya baru mengenal bash dan butuh beberapa saat untuk mencari cara menggunakannya dalam ifpernyataan multi-kondisi . Saya membagikannya di sini kalau-kalau itu membantu seseorang. if [[ ( $file == *.csv ) || ( $file == *.png ) ]]
joelostblom
6
@ cheflo itu bagus untuk beberapa kondisi secara umum. Dalam kasus khusus ini, Anda juga bisa menggunakan if [[ $file =~ .*\.(csv|png) ]]. Ini lebih pendek, lebih jelas, lebih mudah untuk menambahkan ekstensi tambahan dan dapat dengan mudah dibuat dapat dikonfigurasi (dengan meletakkan "csv | png" dalam sebuah variabel).
Jox
4
Anda dapat menempatkan tanda kutip ganda di sekitar file. if [[ "$file" == *.txt ]]Jika file memiliki spasi dalam namanya, kutip ganda diperlukan.
shawnhcorey
Haruskah saya menggunakan jawaban ini alih-alih yang diterima?
Freedo
26

Anda tidak bisa memastikan pada sistem Unix, bahwa file .txt benar-benar file teks. Taruhan terbaik Anda adalah menggunakan "file". Mungkin coba gunakan:

file -ib "$file"

Kemudian Anda dapat menggunakan daftar tipe MIME yang cocok atau parsing bagian pertama MIME di mana Anda mendapatkan barang-barang seperti "teks", "aplikasi", dll.

Eldelshell
sumber
2
Seperti file -i...termasuk penyandian mime, Anda dapat menggunakanfile --mime-type -b ...
Wilf
24

Anda dapat menggunakan perintah "file" jika Anda benar-benar ingin mengetahui informasi tentang file daripada mengandalkan ekstensi.

Jika Anda merasa nyaman menggunakan ekstensi, Anda dapat menggunakan grep untuk melihat apakah ekstensi cocok.

Adam Peck
sumber
ya saya tahu fileperintahnya. Saya sebenarnya telah mencoba mencocokkan berdasarkan pada output dari perintah yang dikatakan ... tapi saya gagal dengan sangat buruk pada pernyataan-pernyataan ini.
17

Anda juga bisa:

   if [ "${FILE##*.}" = "txt" ]; then
       # operation for txt files here
   fi
kvz
sumber
11
case $FILE in *.txt ) ... ;; esacakan tampak lebih kuat dan idiomatis.
tripleee
11

Mirip dengan 'file', gunakan 'mimetype -b' yang sedikit lebih sederhana yang akan berfungsi apa pun ekstensi file.

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

Sunting: Anda mungkin perlu menginstal libfile-mimeinfo-perl pada sistem Anda jika mimetype tidak tersedia

dargaud
sumber
1
Anda harus memperjelas bahwa skrip 'mimetype' tidak tersedia di semua sistem.
gilbertpilz
Selesai, tambah libfile-mimeinfo-perl
dargaud
5

Jawaban yang benar tentang bagaimana mengambil ekstensi yang tersedia dalam nama file di linux adalah:

${filename##*\.} 

Contoh pencetakan semua ekstensi file dalam direktori

for fname in $(find . -maxdepth 1 -type f) # only regular file in the current dir
    do  echo ${fname##*\.} #print extensions 
done
Albin. Com.
sumber
Jawaban Anda menggunakan backslash ganda, tetapi contoh Anda hanya menggunakan backslash tunggal. Contoh Anda benar, jawaban Anda tidak.
gilbertpilz
3

Saya menulis skrip bash yang melihat jenis file kemudian menyalinnya ke lokasi, saya menggunakannya untuk melihat melalui video yang saya tonton online dari cache firefox saya:

#!/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"&

Ini menggunakan ide yang mirip dengan yang disajikan di sini, semoga ini bermanfaat bagi seseorang.

dekode sandi
sumber
2

Saya kira itu '$PATH_TO_SOMEWHERE'seperti sesuatu '<directory>/*'.

Dalam hal ini, saya akan mengubah kode ke:

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

Jika Anda ingin melakukan sesuatu yang lebih rumit dengan direktori dan nama file teks, Anda dapat:

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

Jika Anda memiliki spasi pada nama file Anda, Anda dapat:

find <directory> -maxdepth 1 -type d | xargs ...
find <directory> -maxdepth 1 -type f -name "*.txt" | xargs ...
jfg956
sumber
Ini adalah contoh yang bagus tentang bagaimana Anda melakukan 'loop' di shell. Eksplisit fordan whileloop sebaiknya disediakan ketika loop body perlu lebih kompleks.