बैश स्क्रिप्ट में फ़ाइल नाम के विस्तार की जांच कैसे करें?


170

मैं एक रात का निर्माण स्क्रिप्ट बैश में लिख रहा हूँ।
सब कुछ ठीक है और एक छोटे रोड़ा को छोड़कर बांका है:


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

मेरी समस्या फ़ाइल एक्सटेंशन को निर्धारित करना और फिर उसके अनुसार कार्य करना है। मुझे पता है कि मुद्दा एक बयान में है, एक txt फ़ाइल के लिए परीक्षण।

यदि कोई फ़ाइल .txt प्रत्यय है, तो मैं कैसे निर्धारित कर सकता हूं?


यह टूट जाएगा यदि आपके पास इसके नाम की जगह के साथ एक फ़ाइल है।
jfg956

पॉल के जवाब के अलावा, आप उपयोग कर सकते हैं $(dirname $PATH_TO_SOMEWHERE)और $(basename $PATH_TO_SOMEWHERE)फ़ोल्डर और निर्देशिका में विभाजित करने के लिए और कुछ निर्देशिका-ईश और फ़ाइल-ईश करते हैं
McPeppr

जवाबों:


249

मुझे लगता है कि आप कहना चाहते हैं "क्या $ फ़ाइल के अंतिम चार वर्ण समान हैं .txt?" यदि हां, तो आप निम्नलिखित का उपयोग कर सकते हैं:

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

ध्यान दें कि ': -' संशोधक का अर्थ कुछ अलग होने के बीच की जगह file:और -4आवश्यक है।


1
उस छोर तक, आप एक विंडोज़ मशीन पर भी कमांड.टेक्स्ट को कमोडिक्स का नाम बदल सकते हैं।
गृहनगर

9
यदि आप एक असमानता को निर्दिष्ट करना चाहते हैं, तो अतिरिक्त ब्रैकेट को शामिल करना याद रखें: यदि [[$ {फ़ाइल: -4}! = ".Txt"]]
23:13 पर राम राजमणि

4
@RamRajamony असमानता का परीक्षण करते समय [[[क्यों उपयोग करना आवश्यक है?
पेसा

मैं इंगित करना चाहता था कि बृहदान्त्र के बाद का स्थान महत्वपूर्ण है। ${var:-4}जैसा है वैसा नहीं है ${var: -4}; पहला (बिना स्थान के) का विस्तार '-4' के रूप में होगा यदि var दूसरा है (स्पेस के साथ) var के अंतिम 4 वर्ण देता है।
pbatey

1
बैश में, यह "[: ==: unary ऑपरेटर अपेक्षित" त्रुटि उत्पन्न करेगा जब तक कि आप पहले चर के आसपास उद्धरण नहीं देते। इसलिए if [ "${file: -4}" == ".txt" ]इसके बजाय।
गाइल्स बी

264

बनाना

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

इस तरह:

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

यानी डबल कोष्ठक और कोई उद्धरण नहीं।

दाईं ओर ==एक शेल पैटर्न है। यदि आपको एक नियमित अभिव्यक्ति की आवश्यकता है, =~तो उपयोग करें ।


15
मुझे इस बारे में पता नहीं था। यह एक विशेष मामला प्रतीत होता है कि दाईं ओर == या! = को शेल पैटर्न के रूप में विस्तारित किया गया है। व्यक्तिगत रूप से मुझे लगता है कि यह मेरे उत्तर से अधिक स्पष्ट है।
पॉल स्टीफेंसन

20
मैं कोसने के लिए नया हूं और मुझे यह जानने में थोड़ा समय लगा कि मुझे बहु-सशर्त ifबयान में इसका उपयोग कैसे करना है । मैं इसे यहाँ साझा कर रहा हूँ अगर यह किसी की मदद करता है। if [[ ( $file == *.csv ) || ( $file == *.png ) ]]
joelostblom

6
@cheflo सामान्य स्थिति में कई स्थितियों के लिए अच्छा है। इस विशिष्ट मामले में, आप भी उपयोग कर सकते हैं if [[ $file =~ .*\.(csv|png) ]]। यह छोटा है, स्पष्ट है, अतिरिक्त एक्सटेंशन जोड़ना आसान है और इसे आसानी से विन्यास योग्य बनाया जा सकता है (एक चर में "csv | png" डालकर)।
jox

4
आप फ़ाइल के चारों ओर दोहरे उद्धरण रख सकते हैं। if [[ "$file" == *.txt ]]यदि फ़ाइल के नाम में रिक्त स्थान है, तो दोहरे-उद्धरण की आवश्यकता है।
शॉनहॉर्की 11

क्या मुझे स्वीकृत उत्तर के बजाय इस उत्तर का उपयोग करना चाहिए?
2

26

आप सिर्फ यूनिक्स प्रणाली पर यकीन नहीं कर सकते, कि एक .txt फ़ाइल वास्तव में एक पाठ फ़ाइल है। आपकी सबसे अच्छी शर्त "फ़ाइल" का उपयोग करना है। शायद उपयोग करने का प्रयास करें:

file -ib "$file"

तब आप MIME के ​​पहले भाग के साथ मेल खाने या पार्स करने के लिए MIME प्रकारों की एक सूची का उपयोग कर सकते हैं जहाँ आपको "text", "application", आदि जैसे सामान मिलते हैं।


2
जैसा file -i...कि माइम एन्कोडिंग शामिल है, आप उपयोग कर सकते हैंfile --mime-type -b ...
विल्फ

24

यदि आप वास्तव में एक्सटेंशन पर भरोसा करने के बजाय फ़ाइल के बारे में जानकारी प्राप्त करना चाहते हैं तो आप "फाइल" कमांड का उपयोग कर सकते हैं।

यदि आप एक्सटेंशन का उपयोग करके सहज महसूस करते हैं तो आप यह देखने के लिए कि क्या यह मेल खाता है, grep का उपयोग कर सकता है।


हाँ मैं fileकमांड से अवगत हूँ । मैंने वास्तव में उक्त कमांड के आउटपुट के आधार पर मिलान करने की कोशिश की थी ... लेकिन मैं इन इफ-स्टेटमेंट्स पर बुरी तरह विफल रहा।

17

आप भी कर सकते हैं:

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

11
case $FILE in *.txt ) ... ;; esacअधिक मजबूत और मुहावरेदार प्रतीत होगा।
ट्रिपल डे

11

'फ़ाइल' के समान, थोड़ा सरल 'mimetype -b' का उपयोग करें, जो फ़ाइल एक्सटेंशन के बिना काम करेगा।

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

संपादित करें: यदि आपके पास mimetype उपलब्ध नहीं है, तो आपको अपने सिस्टम पर libfile-mimeinfo-perl इंस्टॉल करना पड़ सकता है


1
आपको यह स्पष्ट कर देना चाहिए कि 'mimetype' स्क्रिप्ट सभी प्रणालियों पर उपलब्ध नहीं है।
गिल्बर्टपिल्ज़

हो गया, libfile-mimeinfo-perl
dargaud

5

लिनक्स में फ़ाइल नाम में उपलब्ध एक्सटेंशन को लेने का सही उत्तर है:

${filename##*\.} 

एक निर्देशिका में सभी फ़ाइल एक्सटेंशन प्रिंट करने का उदाहरण

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

आपका उत्तर दोहरा बैकलैश का उपयोग करता है, लेकिन आपका उदाहरण केवल एक बैकस्लैश का उपयोग करता है। आपका उदाहरण सही है, आपका उत्तर नहीं है।
गिल्बर्टपिलज़

3

मैंने एक बैश स्क्रिप्ट लिखी है जो किसी फ़ाइल के प्रकार को देखती है और फिर उसे किसी स्थान पर कॉपी कर देती है, मैं इसका उपयोग अपने फ़ायरफ़ॉक्स कैश से ऑनलाइन देखे गए वीडियो के माध्यम से देखने के लिए करता हूँ:

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

यह यहां प्रस्तुत लोगों के समान विचारों का उपयोग करता है, आशा है कि यह किसी के लिए उपयोगी है।


2

मुझे लगता है कि '$PATH_TO_SOMEWHERE'ऐसा कुछ है '<directory>/*'

इस स्थिति में, मैं कोड को इसमें बदल दूंगा:

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

यदि आप निर्देशिका और पाठ फ़ाइल नामों के साथ कुछ अधिक जटिल करना चाहते हैं, तो आप कर सकते हैं:

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

यदि आपके फ़ाइल नामों में स्थान हैं, तो आप निम्न कार्य कर सकते हैं:

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

आप शेल में 'लूप्स' कैसे करते हैं, ये महान उदाहरण हैं। जब लूप बॉडी को और अधिक जटिल बनाने की आवश्यकता होती है, तो स्पष्ट forऔर whileलूप बेहतर तरीके से आरक्षित होते हैं।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.