Làm cách nào để kiểm tra phần mở rộng của tên tệp trong tập lệnh bash?


170

Tôi đang viết một kịch bản xây dựng hàng đêm trong bash.
Mọi thứ đều ổn và bảnh bao trừ một chút khó khăn:


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

Vấn đề của tôi là xác định phần mở rộng tập tin và sau đó hành động phù hợp. Tôi biết vấn đề nằm ở câu lệnh if, đang kiểm tra tệp txt.

Làm cách nào để xác định xem một tệp có hậu tố .txt không?


Điều này sẽ phá vỡ nếu bạn có một tệp có một khoảng trắng trong tên của nó.
jfg956

Ngoài câu trả lời của Paul, bạn có thể sử dụng $(dirname $PATH_TO_SOMEWHERE)$(basename $PATH_TO_SOMEWHERE)phân chia thành thư mục và thư mục và làm một cái gì đó thư mục-ish và file-ish
McPeppr

Câu trả lời:


248

Tôi nghĩ bạn muốn nói "Bốn ký tự cuối cùng của tệp $ có bằng .txtkhông?" Nếu vậy, bạn có thể sử dụng như sau:

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

Lưu ý rằng khoảng trắng giữa file:-4được yêu cầu, vì công cụ sửa đổi ': -' có nghĩa là một cái gì đó khác nhau.


1
để kết thúc, bạn cũng có thể đổi tên Command.com thành Command.txt trên máy windows.
quê hương

9
Nếu bạn muốn chỉ định một bất đẳng thức, hãy nhớ bao gồm thêm dấu ngoặc: if [[$ {file: -4}! = "
.Txt

4
@RamRajamony Tại sao cần phải sử dụng [[khi kiểm tra bất đẳng thức?
PesaThe 8/12/17

Tôi muốn chỉ ra rằng không gian sau dấu hai chấm là quan trọng. ${var:-4}không giống như ${var: -4}; cái đầu tiên (không có khoảng trắng) sẽ mở rộng thành '-4' nếu var không đặt thứ hai (có khoảng trắng) trả về 4 ký tự cuối cùng của var.
pbatey

1
Trong bash, điều này sẽ tạo ra lỗi "[: ==: toán tử đơn vị dự kiến" trừ khi bạn đặt dấu ngoặc kép quanh biến đầu tiên. Vì vậy, if [ "${file: -4}" == ".txt" ]thay vào đó.
Giles B

264

Làm

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

như thế này:

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

Đó là, dấu ngoặc kép và không có dấu ngoặc kép.

Phía bên phải ==là một mẫu vỏ. Nếu bạn cần một biểu thức chính quy, sử dụng =~sau đó.


15
Tôi không biết về điều này. Có vẻ như đây là trường hợp đặc biệt mà phía bên phải của == hoặc! = Được mở rộng dưới dạng mẫu vỏ. Cá nhân tôi nghĩ rằng điều này rõ ràng hơn câu trả lời của tôi.
Paul Stephenson

20
Tôi mới sử dụng bash và tôi phải mất một chút thời gian để tìm ra cách sử dụng điều này trong một iftuyên bố đa điều kiện . Tôi đang chia sẻ nó ở đây trong trường hợp nó giúp được ai đó. if [[ ( $file == *.csv ) || ( $file == *.png ) ]]
joelostblom 7/2/2015

6
@cheflo điều đó tốt cho nhiều điều kiện nói chung. Trong trường hợp cụ thể này, bạn cũng có thể sử dụng if [[ $file =~ .*\.(csv|png) ]]. Nó ngắn hơn, rõ ràng hơn, dễ dàng hơn để thêm các tiện ích mở rộng bổ sung và có thể dễ dàng định cấu hình (bằng cách đặt "csv | png" vào một biến).
Jox

4
Bạn có thể đặt dấu ngoặc kép xung quanh tập tin. if [[ "$file" == *.txt ]]Nếu tệp có khoảng trắng trong tên của nó, yêu cầu trích dẫn kép.
Shawnhcorey

Tôi có nên sử dụng câu trả lời này thay vì câu trả lời được chấp nhận?
Freedo

26

Bạn không thể chắc chắn trên một hệ thống Unix, rằng tệp .txt thực sự là một tệp văn bản. Đặt cược tốt nhất của bạn là sử dụng "tập tin". Có thể thử sử dụng:

file -ib "$file"

Sau đó, bạn có thể sử dụng danh sách các loại MIME để đối chiếu hoặc phân tích phần đầu tiên của MIME nơi bạn nhận được các nội dung như "văn bản", "ứng dụng", v.v.


2
Như file -i...bao gồm mã hóa kịch câm, bạn có thể sử dụngfile --mime-type -b ...
Wilf

24

Bạn có thể sử dụng lệnh "tệp" nếu bạn thực sự muốn tìm hiểu thông tin về tệp thay vì dựa vào các tiện ích mở rộng.

Nếu bạn cảm thấy thoải mái với việc sử dụng tiện ích mở rộng, bạn có thể sử dụng grep để xem nó có phù hợp không.


vâng tôi biết file lệnh Tôi thực sự đã thử kết hợp dựa trên đầu ra của lệnh đã nói ... nhưng tôi thất bại khủng khiếp với những câu lệnh if này.

17

Bạn cũng có thể làm:

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

11
case $FILE in *.txt ) ... ;; esacsẽ có vẻ mạnh mẽ và thành ngữ hơn.
tripleee

11

Tương tự như 'tệp', sử dụng 'mimetype -b' đơn giản hơn một chút sẽ hoạt động bất kể phần mở rộng tệp.

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

Chỉnh sửa: bạn có thể cần cài đặt libfile-mimeinfo-perl trên hệ thống của mình nếu không có sẵn mimetype


1
Bạn nên làm rõ rằng tập lệnh 'mimetype' không có sẵn trên tất cả các hệ thống.
gilbertpilz

Xong, thêm libfile-mimeinfo-perl
dargaud

5

Câu trả lời đúng về cách lấy phần mở rộng có sẵn trong tên tệp trong linux là:

${filename##*\.} 

Ví dụ về in tất cả các phần mở rộng tập tin trong một thư mục

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

Câu trả lời của bạn sử dụng dấu gạch chéo kép, nhưng ví dụ của bạn chỉ sử dụng dấu gạch chéo ngược đơn. Ví dụ của bạn là chính xác, câu trả lời của bạn là không.
gilbertpilz

3

Tôi đã viết một tập lệnh bash nhìn vào loại tệp sau đó sao chép nó vào một vị trí, tôi sử dụng nó để xem qua các video tôi đã xem trực tuyến từ bộ nhớ cache firefox của mình:

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

Nó sử dụng những ý tưởng tương tự như những ý tưởng được trình bày ở đây, hy vọng điều này hữu ích cho ai đó.


2

Tôi đoán đó '$PATH_TO_SOMEWHERE'là một cái gì đó như'<directory>/*' .

Trong trường hợp này, tôi sẽ thay đổi mã thành:

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

Nếu bạn muốn làm một cái gì đó phức tạp hơn với tên tệp thư mục và văn bản, bạn có thể:

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

Nếu bạn có khoảng trắng trong tên tệp của mình, bạn có thể:

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

Đây là những ví dụ tuyệt vời về cách bạn thực hiện 'vòng lặp' trong vỏ. Rõ ràng forwhilecác vòng lặp tốt hơn được dành riêng khi cơ thể vòng lặp cần phức tạp hơn.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.