bash - बैश में फ़ाइल नाम और विस्तार निकालें




string filenames (20)

जादू फ़ाइल पहचान

इस स्टैक ओवरफ़्लो प्रश्न पर बहुत अच्छे उत्तरों के अलावा मैं जोड़ना चाहता हूं:

लिनक्स और अन्य यूनिक्सन के तहत, file नामक एक जादू कमांड होता है, जो file कुछ बाइट्स का विश्लेषण करके फ़ाइल प्रकार का पता लगाता है। यह एक बहुत पुराना टूल है, प्रारंभिक रूप से प्रिंट सर्वर के लिए उपयोग किया जाता है (यदि इसके लिए नहीं बनाया गया है ... मुझे इसके बारे में निश्चित नहीं है)।

file myfile.txt
myfile.txt: UTF-8 Unicode text

file -b --mime-type myfile.txt
text/plain

मानक एक्सटेंशन /etc/mime.types (मेरे Debian जीएनयू / लिनक्स डेस्कटॉप पर) में पाया जा सकता है। man file और man mime.types देखें। शायद आपको file उपयोगिता और mime-support पैकेज इंस्टॉल करना होगा):

grep $( file -b --mime-type myfile.txt ) </etc/mime.types
text/plain      asc txt text pot brf srt

आप सही एक्सटेंशन निर्धारित करने के लिए एक bash फ़ंक्शन बना सकते हैं। एक छोटा (सही नहीं) नमूना है:

file2ext() {
    local _mimetype=$(file -Lb --mime-type "$1") _line _basemimetype
    case ${_mimetype##*[/.-]} in
        gzip | bzip2 | xz | z )
            _mimetype=${_mimetype##*[/.-]}
            _mimetype=${_mimetype//ip}
            _basemimetype=$(file -zLb --mime-type "$1")
            ;;
        stream )
            _mimetype=($(file -Lb "$1"))
            [ "${_mimetype[1]}" = "compressed" ] &&
                _basemimetype=$(file -b --mime-type - < <(
                        ${_mimetype,,} -d <"$1")) ||
                _basemimetype=${_mimetype,,}
            _mimetype=${_mimetype,,}
            ;;
        executable )  _mimetype='' _basemimetype='' ;;
        dosexec )     _mimetype='' _basemimetype='exe' ;;
        shellscript ) _mimetype='' _basemimetype='sh' ;;
        * )
            _basemimetype=$_mimetype
            _mimetype=''
            ;;
    esac
    while read -a _line ;do
        if [ "$_line" == "$_basemimetype" ] ;then
            [ "$_line[1]" ] &&
                _basemimetype=${_line[1]} ||
                _basemimetype=${_basemimetype##*[/.-]}
            break
        fi
        done </etc/mime.types
    case ${_basemimetype##*[/.-]} in
        executable ) _basemimetype='' ;;
        shellscript ) _basemimetype='sh' ;;
        dosexec ) _basemimetype='exe' ;;
        * ) ;;
    esac
    [ "$_mimetype" ] && [ "$_basemimetype" != "$_mimetype" ] &&
      printf ${2+-v} $2 "%s.%s" ${_basemimetype##*[/.-]} ${_mimetype##*[/.-]} ||
      printf ${2+-v} $2 "%s" ${_basemimetype##*[/.-]}
}

यह फ़ंक्शन एक बैश वैरिएबल सेट कर सकता है जिसे बाद में उपयोग किया जा सकता है:

(यह @ पेटेश सही जवाब से प्रेरित है):

filename=$(basename "$fullfile")
filename="${filename%.*}"
file2ext "$fullfile" extension

echo "$fullfile -> $filename . $extension"

मैं फ़ाइल नाम (एक्सटेंशन के बिना) और एक्सटेंशन को अलग से प्राप्त करना चाहता हूं।

अब तक का सबसे अच्छा समाधान यह है:

NAME=`echo "$FILE" | cut -d'.' -f1`
EXTENSION=`echo "$FILE" | cut -d'.' -f2`

यह गलत है क्योंकि फ़ाइल नाम में एकाधिक "।" होने पर यह काम नहीं करता है। वर्ण। यदि, मान लीजिए, मेरे पास abjs है और यह ab और js के बजाय, a और b.js पर विचार करेगा।

इसे पाइथन में आसानी से किया जा सकता है

file, ext = os.path.splitext(path)

लेकिन अगर संभव हो तो मैं इसके लिए सिर्फ एक पायथन दुभाषिया को आग नहीं करना चाहूंगा।

कोई बेहतर विचार?


[एक लाइनर से एक जेनेरिक बैश फ़ंक्शन में संशोधित, व्यवहार अब dirname और basename उपयोगिता के अनुरूप है; तर्क जोड़ा गया।]

स्वीकार्य उत्तर ठेठ मामलों में अच्छी तरह से काम करता है , लेकिन किनारे के मामलों में विफल रहता है , अर्थात्:

  • एक्सटेंशन के बिना फ़ाइल नामों के लिए (इस उत्तर के शेष में प्रत्यय कहा जाता है), extension=${filename##*.} खाली स्ट्रिंग के बजाय इनपुट फ़ाइल नाम देता है।
  • extension=${filename##*.} प्रारंभिक शामिल नहीं है . , सम्मेलन के विपरीत।
    • अंधेरे से तैयार करना प्रत्यय के बिना फ़ाइल नामों के लिए काम नहीं करेगा।
  • filename="${filename%.*}" इनपुट फ़ाइल नाम से शुरू होने पर खाली स्ट्रिंग होगी . और आगे नहीं है . पात्र (उदाहरण के लिए, .bash_profile ) - सम्मेलन के विपरीत।

---------

इस प्रकार, एक मजबूत समाधान की जटिलता जो सभी किनारे मामलों को कवर करती है, एक समारोह के लिए कॉल करती है - नीचे इसकी परिभाषा देखें; यह पथ के सभी घटकों को वापस कर सकता है

उदाहरण कॉल:

splitPath '/etc/bash.bashrc' dir fname fnameroot suffix
# -> $dir == '/etc'
# -> $fname == 'bash.bashrc'
# -> $fnameroot == 'bash'
# -> $suffix == '.bashrc'

ध्यान दें कि इनपुट पथ के बाद तर्क स्वतंत्र रूप से चुने जाते हैं, स्थितित्मक चर नाम
उन लोगों के सामने आने वाले ब्याज की चर को छोड़ने के लिए, _ निर्दिष्ट करें (फेंक-वेरिएबल $_ का उपयोग करने के लिए) या '' ; उदाहरण के लिए, केवल फ़ाइल नाम रूट और एक्सटेंशन निकालने के लिए, splitPath '/etc/bash.bashrc' _ _ fnameroot extension

# SYNOPSIS
#   splitPath path varDirname [varBasename [varBasenameRoot [varSuffix]]] 
# DESCRIPTION
#   Splits the specified input path into its components and returns them by assigning
#   them to variables with the specified *names*.
#   Specify '' or throw-away variable _ to skip earlier variables, if necessary.
#   The filename suffix, if any, always starts with '.' - only the *last*
#   '.'-prefixed token is reported as the suffix.
#   As with `dirname`, varDirname will report '.' (current dir) for input paths
#   that are mere filenames, and '/' for the root dir.
#   As with `dirname` and `basename`, a trailing '/' in the input path is ignored.
#   A '.' as the very first char. of a filename is NOT considered the beginning
#   of a filename suffix.
# EXAMPLE
#   splitPath '/home/jdoe/readme.txt' parentpath fname fnameroot suffix
#   echo "$parentpath" # -> '/home/jdoe'
#   echo "$fname" # -> 'readme.txt'
#   echo "$fnameroot" # -> 'readme'
#   echo "$suffix" # -> '.txt'
#   ---
#   splitPath '/home/jdoe/readme.txt' _ _ fnameroot
#   echo "$fnameroot" # -> 'readme'  
splitPath() {
  local _sp_dirname= _sp_basename= _sp_basename_root= _sp_suffix=
    # simple argument validation
  (( $# >= 2 )) || { echo "$FUNCNAME: ERROR: Specify an input path and at least 1 output variable name." >&2; exit 2; }
    # extract dirname (parent path) and basename (filename)
  _sp_dirname=$(dirname "$1")
  _sp_basename=$(basename "$1")
    # determine suffix, if any
  _sp_suffix=$([[ $_sp_basename = *.* ]] && printf %s ".${_sp_basename##*.}" || printf '')
    # determine basename root (filemane w/o suffix)
  if [[ "$_sp_basename" == "$_sp_suffix" ]]; then # does filename start with '.'?
      _sp_basename_root=$_sp_basename
      _sp_suffix=''
  else # strip suffix from filename
    _sp_basename_root=${_sp_basename%$_sp_suffix}
  fi
  # assign to output vars.
  [[ -n $2 ]] && printf -v "$2" "$_sp_dirname"
  [[ -n $3 ]] && printf -v "$3" "$_sp_basename"
  [[ -n $4 ]] && printf -v "$4" "$_sp_basename_root"
  [[ -n $5 ]] && printf -v "$5" "$_sp_suffix"
  return 0
}

test_paths=(
  '/etc/bash.bashrc'
  '/usr/bin/grep'
  '/Users/jdoe/.bash_profile'
  '/Library/Application Support/'
  'readme.new.txt'
)

for p in "${test_paths[@]}"; do
  echo ----- "$p"
  parentpath= fname= fnameroot= suffix=
  splitPath "$p" parentpath fname fnameroot suffix
  for n in parentpath fname fnameroot suffix; do
    echo "$n=${!n}"
  done
done

टेस्ट कोड जो फ़ंक्शन का उपयोग करता है:

test_paths=(
  '/etc/bash.bashrc'
  '/usr/bin/grep'
  '/Users/jdoe/.bash_profile'
  '/Library/Application Support/'
  'readme.new.txt'
)

for p in "${test_paths[@]}"; do
  echo ----- "$p"
  parentpath= fname= fnameroot= suffix=
  splitPath "$p" parentpath fname fnameroot suffix
  for n in parentpath fname fnameroot suffix; do
    echo "$n=${!n}"
  done
done

अपेक्षित आउटपुट - किनारे के मामलों पर ध्यान दें:

  • एक फ़ाइल नाम कोई प्रत्यय नहीं है
  • एक फ़ाइल नाम से शुरू हो रहा है . (प्रत्यय की शुरुआत नहीं माना जाता है)
  • एक इनपुट पथ / में समाप्त होता है (पीछे / अनदेखा किया जाता है)
  • एक इनपुट पथ जो केवल एक फ़ाइल नाम है ( . पैरेंट पथ के रूप में वापस किया जाता है)
  • एक फ़ाइल नाम जो से अधिक है . -prefixed टोकन (केवल अंतिम प्रत्यय माना जाता है):
----- /etc/bash.bashrc
parentpath=/etc
fname=bash.bashrc
fnameroot=bash
suffix=.bashrc
----- /usr/bin/grep
parentpath=/usr/bin
fname=grep
fnameroot=grep
suffix=
----- /Users/jdoe/.bash_profile
parentpath=/Users/jdoe
fname=.bash_profile
fnameroot=.bash_profile
suffix=
----- /Library/Application Support/
parentpath=/Library
fname=Application Support
fnameroot=Application Support
suffix=
----- readme.new.txt
parentpath=.
fname=readme.new.txt
fnameroot=readme.new
suffix=.txt

आप POSIX चर के जादू का उपयोग कर सकते हैं:

bash-3.2$ FILENAME=somefile.tar.gz
bash-3.2$ echo ${FILENAME%%.*}
somefile
bash-3.2$ echo ${FILENAME%.*}
somefile.tar

उसमें एक चेतावनी है यदि आपका फ़ाइल नाम फॉर्म का था ./somefile.tar.gz फिर echo ${FILENAME%%.*} , जो ./somefile.tar.gz से सबसे लंबे मैच को हटा देगा . और आपके पास खाली स्ट्रिंग होगी।

(आप अस्थायी चर के साथ उस पर काम कर सकते हैं:

FULL_FILENAME=$FILENAME
FILENAME=${FULL_FILENAME##*/}
echo ${FILENAME%%.*}

)

यह site बताती है।

${variable%pattern}
  Trim the shortest match from the end
${variable##pattern}
  Trim the longest match from the beginning
${variable%%pattern}
  Trim the longest match from the end
${variable#pattern}
  Trim the shortest match from the beginning

आप उपयोग कर सकते हैं

sed 's/^/./' | rev | cut -d. -f2- | rev | cut -c2-

to get file name and

sed 's/^/./' | rev | cut -d. -f1  | rev

to get extension.

Test case:

echo "filename.gz"     | sed 's/^/./' | rev | cut -d. -f2- | rev | cut -c2-
echo "filename.gz"     | sed 's/^/./' | rev | cut -d. -f1  | rev
echo "filename"        | sed 's/^/./' | rev | cut -d. -f2- | rev | cut -c2-
echo "filename"        | sed 's/^/./' | rev | cut -d. -f1  | rev
echo "filename.tar.gz" | sed 's/^/./' | rev | cut -d. -f2- | rev | cut -c2-
echo "filename.tar.gz" | sed 's/^/./' | rev | cut -d. -f1  | rev

आप सभी फ़ील्ड प्रदर्शित करने के लिए कटौती कर सकते हैं और बाद में जोड़ सकते हैं - फ़ील्ड नंबर पर।

NAME=`basename "$FILE"`
EXTENSION=`echo "$NAME" | cut -d'.' -f2-`

तो अगर FILE eth0.pcap.gz , तो एक्सटेंशन pcap.gz होगा

उसी तर्क का उपयोग करके, आप निम्नानुसार कट के साथ '-' का उपयोग कर फ़ाइल नाम भी प्राप्त कर सकते हैं:

NAME=`basename "$FILE" | cut -d'.' -f-1`

यह उन फ़ाइल नामों के लिए भी काम करता है जिनमें कोई एक्सटेंशन नहीं है।


आम तौर पर आप पहले ही एक्सटेंशन को जानते हैं, इसलिए आप इसका उपयोग करना चाहेंगे:

basename filename .extension

उदाहरण के लिए:

basename /path/to/dir/filename.txt .txt

और हम पाते हैं

filename

एक साधारण जवाब:

POSIX चर के उत्तर पर विस्तार करने के लिए, ध्यान दें कि आप अधिक दिलचस्प पैटर्न कर सकते हैं। तो यहां विस्तृत मामले के लिए, आप बस यह कर सकते हैं:

tar -zxvf $1
cd ${1%.tar.*}

वह .tar की आखिरी घटना को काट देगा। <कुछ>

अधिक आम तौर पर, यदि आप की अंतिम घटना को हटाना चाहते थे। <कुछ><कुछ और> फिर

${1.*.*}

ठीक काम करना चाहिए।

उपरोक्त उत्तर का लिंक मृत प्रतीत होता है। यहां स्ट्रिंग मैनिपुलेशन के समूह का एक बड़ा स्पष्टीकरण है जो आप सीधे टीएलडीपी से बैश में कर सकते हैं


ऐसा लगता है कि फ़ाइल में कोई एक्सटेंशन नहीं है, या कोई फ़ाइल नाम नहीं है। यहां मैं जो उपयोग कर रहा हूं; यह केवल बिल्टिन का उपयोग करता है और अधिक (लेकिन सभी नहीं) पैथोलॉजिकल फ़ाइल नामों को संभालता है।

#!/bin/bash
for fullpath in "[email protected]"
do
    filename="${fullpath##*/}"                      # Strip longest match of */ from start
    dir="${fullpath:0:${#fullpath} - ${#filename}}" # Substring from 0 thru pos of filename
    base="${filename%.[^.]*}"                       # Strip shortest match of . plus at least one non-dot char from end
    ext="${filename:${#base} + 1}"                  # Substring from len of base thru end
    if [[ -z "$base" && -n "$ext" ]]; then          # If we have an extension and no base, it's really the base
        base=".$ext"
        ext=""
    fi

    echo -e "$fullpath:\n\tdir  = \"$dir\"\n\tbase = \"$base\"\n\text  = \"$ext\""
done

और यहां कुछ टेस्टकेस हैं:

$ basename-and-extension.sh / /home/me/ /home/me/file /home/me/file.tar /home/me/file.tar.gz /home/me/.hidden /home/me/.hidden.tar /home/me/.. .
/:
    dir  = "/"
    base = ""
    ext  = ""
/home/me/:
    dir  = "/home/me/"
    base = ""
    ext  = ""
/home/me/file:
    dir  = "/home/me/"
    base = "file"
    ext  = ""
/home/me/file.tar:
    dir  = "/home/me/"
    base = "file"
    ext  = "tar"
/home/me/file.tar.gz:
    dir  = "/home/me/"
    base = "file.tar"
    ext  = "gz"
/home/me/.hidden:
    dir  = "/home/me/"
    base = ".hidden"
    ext  = ""
/home/me/.hidden.tar:
    dir  = "/home/me/"
    base = ".hidden"
    ext  = "tar"
/home/me/..:
    dir  = "/home/me/"
    base = ".."
    ext  = ""
.:
    dir  = ""
    base = "."
    ext  = ""

मुझे लगता है कि अगर आपको फ़ाइल के नाम की आवश्यकता है, तो आप इसे आजमा सकते हैं:

FULLPATH=/usr/share/X11/xorg.conf.d/50-synaptics.conf

# Remove all the prefix until the "/" character
FILENAME=${FULLPATH##*/}

# Remove all the prefix until the "." character
FILEEXTENSION=${FILENAME##*.}

# Remove a suffix, in our case, the filename. This will return the name of the directory that contains this file.
BASEDIRECTORY=${FULLPATH%$FILENAME}

echo "path = $FULLPATH"
echo "file name = $FILENAME"
echo "file extension = $FILEEXTENSION"
echo "base directory = $BASEDIRECTORY"

और वह सब = डी है।


मेलिन ब्लॉग पोस्ट पर एक टिप्पणी में लिखते हैं:

बैश का उपयोग करके एक्सटेंशन के बिना फ़ाइल नाम प्राप्त करने के लिए ${file%.*} और ${file##*.} अकेले एक्सटेंशन प्राप्त करने के लिए भी है। अर्थात्,

file="thisfile.txt"
echo "filename: ${file%.*}"
echo "extension: ${file##*.}"

आउटपुट:

filename: thisfile
extension: txt

यहां कुछ वैकल्पिक सुझाव दिए गए हैं (ज्यादातर awk ), कुछ उन्नत उपयोग मामलों सहित, सॉफ्टवेयर पैकेज के लिए संस्करण संख्या निकालने जैसे।

f='/path/to/complex/file.1.0.1.tar.gz'

# Filename : 'file.1.0.x.tar.gz'
    echo "$f" | awk -F'/' '{print $NF}'

# Extension (last): 'gz'
    echo "$f" | awk -F'[.]' '{print $NF}'

# Extension (all) : '1.0.1.tar.gz'
    echo "$f" | awk '{sub(/[^.]*[.]/, "", $0)} 1'

# Extension (last-2): 'tar.gz'
    echo "$f" | awk -F'[.]' '{print $(NF-1)"."$NF}'

# Basename : 'file'
    echo "$f" | awk '{gsub(/.*[/]|[.].*/, "", $0)} 1'

# Basename-extended : 'file.1.0.1.tar'
    echo "$f" | awk '{gsub(/.*[/]|[.]{1}[^.]+$/, "", $0)} 1'

# Path : '/path/to/complex/'
    echo "$f" | awk '{match($0, /.*[/]/, a); print a[0]}'
    # or 
    echo "$f" | grep -Eo '.*[/]'

# Folder (containing the file) : 'complex'
    echo "$f" | awk -F'/' '{$1=""; print $(NF-1)}'

# Version : '1.0.1'
    # Defined as 'number.number' or 'number.number.number'
    echo "$f" | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?'

    # Version - major : '1'
    echo "$f" | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' | cut -d. -f1

    # Version - minor : '0'
    echo "$f" | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' | cut -d. -f2

    # Version - patch : '1'
    echo "$f" | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' | cut -d. -f3

# All Components : "path to complex file 1 0 1 tar gz"
    echo "$f" | awk -F'[/.]' '{$1=""; print $0}'

# Is absolute : True (exit-code : 0)
    # Return true if it is an absolute path (starting with '/' or '~/'
    echo "$f" | grep -q '^[/]\|^~/'

इंटरमीडिएट परिणामों के आधार पर सभी उपयोग के मामले इनपुट के रूप में मूल पूर्ण पथ का उपयोग कर रहे हैं।


सबसे छोटा और सरल समाधान (एकल रेखा में) है:

$ file=/blaabla/bla/blah/foo.txt

echo $(basename ${file%.*})

foo


AWK के साथ कोड यहाँ है। यह और अधिक आसानी से किया जा सकता है। लेकिन मैं एडब्ल्यूके में अच्छा नहीं हूं।

filename$ ls
abc.a.txt  a.b.c.txt  pp-kk.txt
filename$ find . -type f | awk -F/ '{print $2}' | rev | awk -F"." '{$1="";print}' | rev | awk 'gsub(" ",".") ,sub(".$", "")'
abc.a
a.b.c
pp-kk
filename$ find . -type f | awk -F/ '{print $2}' | awk -F"." '{print $NF}'
txt
txt
txt

fish में फ़ाइल नाम और विस्तार निकालने के लिए कैसे करें:

function split-filename-extension --description "Prints the filename and extension"
  for file in $argv
    if test -f $file
      set --local extension (echo $file | awk -F. '{print $NF}')
      set --local filename (basename $file .$extension)
      echo "$filename $extension"
    else
      echo "$file is not a valid file"
    end
  end
end

चेतावनी: अंतिम बिंदु पर विभाजन, जो उनके साथ बिंदुओं के साथ फ़ाइल नामों के लिए अच्छी तरह से काम करता है, लेकिन उनमें डॉट्स के साथ एक्सटेंशन के लिए अच्छा नहीं है। नीचे उदाहरण देखें।

उपयोग:

$ split-filename-extension foo-0.4.2.zip bar.tar.gz
foo-0.4.2 zip  # Looks good!
bar.tar gz  # Careful, you probably want .tar.gz as the extension.

ऐसा करने के लिए शायद बेहतर तरीके हैं। इसे सुधारने के लिए मेरे उत्तर को संपादित करने के लिए स्वतंत्र महसूस करें।

यदि एक्सटेंशन का सीमित सेट है तो आप इससे निपटेंगे और आप सभी को जानते हैं, इसे आजमाएं:

switch $file
  case *.tar
    echo (basename $file .tar) tar
  case *.tar.bz2
    echo (basename $file .tar.bz2) tar.bz2
  case *.tar.gz
    echo (basename $file .tar.gz) tar.gz
  # and so on
end

इसमें पहली उदाहरण के रूप में चेतावनी नहीं है, लेकिन आपको हर मामले को संभालना होगा ताकि आप कितने एक्सटेंशन की उम्मीद कर सकें, यह अधिक कठिन हो सकता है।


From the answers above, the shortest oneliner to mimic Python's

file, ext = os.path.splitext(path)

presuming your file really does have an extension, is

EXT="${PATH##*.}"; FILE=$(basename "$PATH" .$EXT)

Here is the algorithm I used for finding the name and extension of a file when I wrote a Bash script to make names unique when names conflicted with respect to casing.

#! /bin/bash 

#
# Finds 
# -- name and extension pairs
# -- null extension when there isn't an extension.
# -- Finds name of a hidden file without an extension
# 

declare -a fileNames=(
  '.Montreal' 
  '.Rome.txt' 
  'Loundon.txt' 
  'Paris' 
  'San Diego.txt'
  'San Francisco' 
  )

echo "Script ${0} finding name and extension pairs."
echo 

for theFileName in "${fileNames[@]}"
do
     echo "theFileName=${theFileName}"  

     # Get the proposed name by chopping off the extension
     name="${theFileName%.*}"

     # get extension.  Set to null when there isn't an extension
     # Thanks to mklement0 in a comment above.
     extension=$([[ "$theFileName" == *.* ]] && echo ".${theFileName##*.}" || echo '')

     # a hidden file without extenson?
     if [ "${theFileName}" = "${extension}" ] ; then
         # hidden file without extension.  Fixup.
         name=${theFileName}
         extension=""
     fi

     echo "  name=${name}"
     echo "  extension=${extension}"
done 

The test run.

$ config/Name\&Extension.bash 
Script config/Name&Extension.bash finding name and extension pairs.

theFileName=.Montreal
  name=.Montreal
  extension=
theFileName=.Rome.txt
  name=.Rome
  extension=.txt
theFileName=Loundon.txt
  name=Loundon
  extension=.txt
theFileName=Paris
  name=Paris
  extension=
theFileName=San Diego.txt
  name=San Diego
  extension=.txt
theFileName=San Francisco
  name=San Francisco
  extension=
$ 

FYI: The complete transliteration program and more test cases can be found here: https://www.dropbox.com/s/4c6m0f2e28a1vxf/avoid-clashes-code.zip?dl=0


In order to make dir more useful (in the case a local file with no path is specified as input) I did the following:

# Substring from 0 thru pos of filename
dir="${fullpath:0:${#fullpath} - ${#filename}}"
if [[ -z "$dir" ]]; then
    dir="./"
fi

This allows you to do something useful like add a suffix to the input file basename as:

outfile=${dir}${base}_suffix.${ext}

testcase: foo.bar
dir: "./"
base: "foo"
ext: "bar"
outfile: "./foo_suffix.bar"

testcase: /home/me/foo.bar
dir: "/home/me/"
base: "foo"
ext: "bar"
outfile: "/home/me/foo_suffix.bar"

Petesh उत्तर से बिल्डिंग, अगर केवल फ़ाइल नाम की आवश्यकता है, तो पथ और एक्सटेंशन दोनों को एक पंक्ति में अलग किया जा सकता है,

filename=$(basename ${fullname%.*})

$ F = "text file.test.txt"  
$ echo ${F/*./}  
txt  

यह फ़ाइल नाम में एकाधिक बिंदुओं और रिक्त स्थानों को पूरा करता है, हालांकि यदि कोई एक्सटेंशन नहीं है तो यह फ़ाइल नाम स्वयं लौटाता है। हालांकि जांचना आसान है; बस फ़ाइल नाम और विस्तार के लिए परीक्षण करें।

स्वाभाविक रूप से यह विधि .tar.gz फ़ाइलों के लिए काम नहीं करती है। हालांकि इसे दो चरणों की प्रक्रिया में संभाला जा सकता है। यदि एक्सटेंशन gz है तो फिर यह देखने के लिए जांचें कि क्या टैर एक्सटेंशन भी है या नहीं।


pax> echo a.b.js | sed 's/\.[^.]*$//'
a.b
pax> echo a.b.js | sed 's/^.*\.//'
js

ठीक काम करता है, तो आप इसका उपयोग कर सकते हैं:

pax> FILE=a.b.js
pax> NAME=$(echo "$FILE" | sed 's/\.[^.]*$//')
pax> EXTENSION=$(echo "$FILE" | sed 's/^.*\.//')
pax> echo $NAME
a.b
pax> echo $EXTENSION
js

वैसे, आदेश, निम्नानुसार काम करते हैं।

NAME लिए आदेश "." प्रतिस्थापित करता है "." चरित्र के बाद किसी भी संख्या में गैर- "." रेखा के अंत तक वर्ण, कुछ भी नहीं (यानी, यह अंतिम से सबकुछ हटा देता है "." रेखा के अंत तक, समावेशी)। यह मूल रूप से रेगेक्स चालबाजी का उपयोग कर एक गैर लालची प्रतिस्थापन है।

EXTENSION लिए आदेश किसी भी संख्या के पात्रों को प्रतिस्थापित करता है "." लाइन की शुरुआत में चरित्र, कुछ भी नहीं (यानी, यह लाइन की शुरुआत से अंतिम बिंदु तक, सब कुछ हटा देता है)। यह एक लालची प्रतिस्थापन है जो डिफ़ॉल्ट कार्रवाई है।





filenames