Extract-bestandsnaam en extensie in BASH

Ik wil de bestandsnaam (zonder extensie) en de uitbreiding afzonderlijk.

De beste oplossing die ik tot nu toe heb gevonden, is:

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

Dit is verkeerd omdat het niet werkt als de bestandsnaam meerdere .tekens. Als, laten we zeggen, ik heb a.b.js, het zal overwegen aen b.js, in plaats van a.ben js.

het kan eenvoudig in Python worden gedaan met

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

Maar ik zou liever niet alleen een Python-tolk voor deze, indien mogelijk maken.

eventuele betere ideeën?


Antwoord 1, Autoriteit 100%

Krijg eerst de bestandsnaam zonder het pad:

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

U kunt ook concentreren op de laatste ‘/’ van het pad in plaats van de ‘.’ die zou moeten werken, zelfs als je onvoorspelbare bestandsuitbreidingen hebt:

filename="${fullfile##*/}"

Mogelijk wilt u de documentatie controleren:


Antwoord 2, Autoriteit 21%

~% FILE="example.tar.gz"
~% echo "${FILE%%.*}"
example
~% echo "${FILE%.*}"
example.tar
~% echo "${FILE#*.}"
tar.gz
~% echo "${FILE##*.}"
gz

Zie voor meer details shell-parameteruitbreidingin de Bash-handleiding.


Antwoord 3, autoriteit 13%

Meestal kent u de extensie al, dus misschien wilt u het volgende gebruiken:

basename filename .extension

bijvoorbeeld:

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

en we krijgen

filename

Antwoord 4, autoriteit 4%

U kunt de magie van POSIX-parameteruitbreiding gebruiken:

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

Er is een voorbehoud dat als uw bestandsnaam de vorm ./somefile.tar.gzhad, echo ${FILENAME%%.*}gretig de langste overeenkomst met de .en je zou de lege tekenreeks hebben.

(Je kunt dat omzeilen met een tijdelijke variabele:

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

)


Deze sitelegt meer uit.

${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

Antwoord 5, Autoriteit 2%

Dat lijkt niet te werken als het bestand geen extensie heeft, of geen bestandsnaam. Hier is wat ik gebruik; Het gebruikt alleen gebouwdeins en verwerkt meer (maar niet alle) pathologische bestandsnamen.

#!/bin/bash
for fullpath in "$@"
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

en hier zijn enkele testcases:

$ 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 = "/"
  basis = ""
  ext = ""
/ Home / ME /:
  DIR = "/ Home / ME /"
  basis = ""
  ext = ""
/ Home / Me / Bestand:
  DIR = "/ Home / ME /"
  basis = "bestand"
  ext = ""
/home/me/file.tar:
  DIR = "/ Home / ME /"
  basis = "bestand"
  ext = "teer"
/home/me/file.tar.gz:
  DIR = "/ Home / ME /"
  basis = "file.tar"
  ext = "gz"
/home/me/.Hidden:
  DIR = "/ Home / ME /"
  basis = ".Hidden"
  ext = ""
/home/me/.hidden.tar:
  DIR = "/ Home / ME /"
  basis = ".Hidden"
  ext = "teer"
/ Home / ME / ..:
  DIR = "/ Home / ME /"
  basis = ".."
  ext = ""
.:
  DIR = ""
  basis = "."
  ext = ""

Antwoord 6

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

werkt prima, dus je kunt gewoon het volgende gebruiken:

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

De commando’s werken trouwens als volgt.

Het commando voor NAMEvervangt een "."teken gevolgd door een willekeurig aantal niet-"."tekens tot aan het einde van de regel, met niets (dwz het verwijdert alles van de laatste "."tot het einde van de regel, inclusief). Dit is in feite een niet-hebzuchtige vervanging met behulp van regex-trucs.

Het commando voor EXTENSIONvervangt een willekeurig aantal tekens gevolgd door een "."teken aan het begin van de regel, met niets (dwz het verwijdert alles van het begin van de regel tot de laatste punt, inclusief). Dit is een hebzuchtige vervanging, wat de standaardactie is.


Antwoord 7

Je kunt basenamegebruiken.

Voorbeeld:

$ basename foo-bar.tar.gz .tar.gz
foo-bar

U moet wel de basisnaam opgeven met de extensie die moet worden verwijderd, maar als u altijd taruitvoert met -z, weet u dat de extensie .tar.gz.

Dit zou moeten doen wat je wilt:

tar -zxvf $1
cd $(basename $1 .tar.gz)

Antwoord 8

Mellen schrijft in een reactie op een blogpost:

Met Bash is er ook ${file%.*}om de bestandsnaam te krijgen zonder de extensie en ${file##*.}om alleen de extensie te krijgen . Dat wil zeggen,

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

Uitgangen:

filename: thisfile
extension: txt

Antwoord 9

Je hoeft je voor deze eenvoudige taak niet bezig te houden met awkof sedof zelfs perl. Er is een pure-Bash, os.path.splitext()-compatibele oplossing die alleen parameteruitbreidingen gebruikt.

Referentie-implementatie

Documentatie van os.path.splitext(path):

Verdeel het pad padnaam in een paar (root, ext)zodat root + ext == path, en extleeg is of begint met een punt en bevat maximaal één punt. Voorlooppunten op de basisnaam worden genegeerd; splitext('.cshrc')geeft ('.cshrc', '')terug.

Python-code:

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

Bash-implementatie

Rekening houden met toonaangevende periodes

root="${path%.*}"
ext="${path#"$root"}"

Voorloopperioden negeren

root="${path#.}";root="${path%"$root"}${root%.*}"
ext="${path#"$root"}"

Testen

Hier zijn testcases voor de implementatie Ignoring leading perioden, die bij elke invoer moet overeenkomen met de Python-referentie-implementatie.

|--------------- | ----------- | -------|
|path           |root       |ext    |
|--------------- | ----------- | -------|
|' .txt'        |' '        |'.txt' |
|' .txt.txt'    |' .txt'    |'.txt' |
|' txt'         |' txt'     |''     |
|'*.txt.txt'    |'*.txt'    |'.txt' |
|'.cshrc'       |'.cshrc'   |''     |
|'.txt'         |'.txt'     |''     |
|'?.txt.txt'    |'?.txt'    |'.txt' |
|'\n.txt.txt'   |'\n.txt'   |'.txt' |
|'\t.txt.txt'   |'\t.txt'   |'.txt' |
|'a b.txt.txt'  |'a b.txt'  |'.txt' |
|'a*b.txt.txt'  |'a*b.txt'  |'.txt' |
|'a?b.txt.txt'  |'a?b.txt'  |'.txt' |
|'a\nb.txt.txt' |'a\nb.txt' |'.txt' |
|'a\tb.txt.txt' |'a\tb.txt' |'.txt' |
|'txt'          |'txt'      |''     |
|'txt.pdf'      |'txt'      |'.pdf' |
|'txt.tar.gz'   |'txt.tar'  |'.gz'  |
|'txt.txt'      |'txt'      |'.txt' |
|--------------- | ----------- | -------|

Testresultaten

Alle tests geslaagd.


Antwoord 10

Je zou de opdracht cutkunnen gebruiken om de laatste twee extensies (de ".tar.gz"deel):

$ echo "foo.tar.gz" | cut -d'.' --complement -f2-
foo

Zoals Clayton Hughes in een opmerking heeft opgemerkt, werkt dit niet voor het daadwerkelijke voorbeeld in de vraag. Dus als alternatief stel ik voor om sedte gebruiken met uitgebreide reguliere expressies, zoals deze:

$ echo "mpc-1.0.1.tar.gz" | sed -r 's/\.[[:alnum:]]+\.[[:alnum:]]+$//'
mpc-1.0.1

Het werkt door de laatste twee (alfanumerieke) extensies onvoorwaardelijk te verwijderen.

[Opnieuw bijgewerkt na commentaar van Anders Lindahl]


Antwoord 11

Het geaccepteerde antwoordwerkt goed in typischegevallen, maar faalt in edgegevallen, namelijk:

  • Voor bestandsnamen zonder extensie (genaamd achtervoegselin de rest van dit antwoord), extension=${filename##*.}retourneert de ingevoerde bestandsnaam in plaats van een lege tekenreeks.
  • extension=${filename##*.}bevat niet de initiële ., in tegenstelling tot de conventie.
    • Blind voorgaand .zou niet werken voor bestandsnamen zonder achtervoegsel.
  • filename="${filename%.*}"zal de lege string zijn, als de invoerbestandsnaam begint met .en verder geen .tekens (bijv. .bash_profile) – in strijd met de conventie.

———

Dus de complexiteit van een robuuste oplossing die alle randgevallen dektvraagt om een functie– zie de definitie hieronder; het kan allecomponenten van een pad teruggeven.

Voorbeeldoproep:

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

Merk op dat de argumenten na het invoerpad vrij gekozen zijn, positionele variabele namen.
Om variabelen over te slaan die niet interessant zijn en die vóór de variabelen komen die dat wel zijn, specificeert u _(om de wegwerpvariabele $_te gebruiken) of ''; bijv. om alleen de bestandsnaam root en extensie te extraheren, gebruikt u 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

Testcode die de functie uitoefent:

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

Verwachte uitvoer – let op de randgevallen:

  • een bestandsnaam zonder achtervoegsel
  • een bestandsnaam die begint met .(nietbeschouwd als het begin van het achtervoegsel)
  • een invoerpad dat eindigt op /(achteraf /wordt genegeerd)
  • een invoerpad dat alleen een bestandsnaam is (.wordt geretourneerd als het bovenliggende pad)
  • een bestandsnaam die meer dan .-voorvoegsel heeft (alleen de laatste wordt als achtervoegsel beschouwd):
----- /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

Antwoord 12

Hier zijn enkele alternatieve suggesties (meestal in awk), inclusief enkele geavanceerde toepassingen, zoals het extraheren van versienummers voor softwarepakketten.

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 '^[/]\|^~/'

Alle use-cases gebruiken het originele volledige pad als invoer, zonder afhankelijk te zijn van tussenresultaten.


Antwoord 13

Kleinste en eenvoudigste oplossing (in één regel) is:

$ file=/blaabla/bla/blah/foo.txt
echo $(basename ${file%.*}) # foo

Antwoord 14

Ik denk dat als je alleen de naam van het bestand nodig hebt, je dit kunt proberen:

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"

En dat is alles =D.


Antwoord 15

U kunt geforceerd knippen om alle velden weer te geven en volgende door -toe te voegen aan het veldnummer.

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

Dus als bestand eth0.pcap.gzis, is de extensie pcap.gz

Met dezelfde logica kunt u ook de bestandsnaam ophalen met ‘-‘ met Snijd als volgt:

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

Dit werkt zelfs voor bestandsnamen die geen extensie hebben.


Antwoord 16

Magic File Recognition

Naast het veel goede antwoorden op deze stapel en nbsp; overloopvraag die ik wil toevoegen:

Onder Linux en andere Unixen is er een Magic -opdracht met de naam file, die Filetype Detectie doen door het analyseren van enkele eerste bytes van het bestand. Dit is een heel oud hulpmiddel, initialiteit gebruikt voor printservers (indien niet gemaakt voor … Ik weet het niet zeker).

file myfile.txt
myfile.txt: UTF-8 Unicode text
file -b --mime-type myfile.txt
text/plain

Standaards-extensies kunnen worden gevonden in /etc/mime.types(op mijn Debian GNU / Linux Desktop. Zie man fileen man mime.types. Misschien moet je de filehulpprogramma en <mime-supportpakketten):

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

U kunt een bash functie voor het bepalen van het bepalen juiste extensie.
Er is een klein (niet perfect) monster:

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##*[/.-]}
}

Deze functie kan een bash-variabele instellen die later kan worden gebruikt:

(dit is geïnspireerd op @Petesh Right Antwoord):

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

Antwoord 17

OK, dus als ik het goed begrijp, is het probleem hier hoe u de naam en de volledige uitbreiding van een bestand krijgt dat meerdere extensies heeft, b.v. stuff.tar.gz.

Dit werkt voor mij:

fullfile="stuff.tar.gz"
fileExt=${fullfile#*.}
fileName=${fullfile%*.$fileExt}

Hiermee geeft u stuffals bestandsnaam en .tar.gzals extensie. Het werkt voor een aantal extensies, waaronder 0. Hoop dat dit helpt voor iedereen die hetzelfde probleem heeft =)


Antwoord 18

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

Dit is geschikt voor meerdere punten en spaties in een bestandsnaam, maar als er geen extensie is, retourneert het de bestandsnaam zelf. Gemakkelijk om te controleren of Test gewoon voor de bestandsnaam en extensie die hetzelfde is.

Natuurlijk werkt deze methode niet voor .tar.gz-bestanden. Het kan echter in een proces van twee stap worden behandeld. Als de extensie GZ is, controleer dan opnieuw om te zien of er ook een teer-extensie is.


Antwoord 19

Ik gebruik het volgende script

$ echo "foo.tar.gz"|rev|cut -d"." -f3-|rev
foo

Antwoord 20

Hoe u de bestandsnaam en uitbreiding in vis :

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

Voorbehoud:Splitst op de laatste punt, wat goed werkt voor bestandsnamen met punten erin, maar niet goed voor extensies met punten erin. Zie voorbeeld hieronder.

Gebruik:

$ 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.

Er zijn waarschijnlijk betere manieren om dit te doen. Voel je vrij om mijn antwoord te bewerken om het te verbeteren.


Als er een beperkt aantal extensies is waarmee u te maken krijgt en u kent ze allemaal, probeer dan dit:

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

Dit heeft niethet voorbehoud als eerste voorbeeld, maar je moet wel elk geval afhandelen, dus het kan vervelender zijn, afhankelijk van hoeveel extensies je kunt verwachten.


Antwoord 21

Hier is code met AWK. Het kan eenvoudiger. Maar ik ben niet goed in 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

Antwoord 22

Gebruik gewoon ${parameter%word}

In jouw geval:

${FILE%.*}

Als je het wilt testen, werkt al het volgende, en verwijder gewoon de extensie:

FILE=abc.xyz; echo ${FILE%.*};
FILE=123.abc.xyz; echo ${FILE%.*};
FILE=abc; echo ${FILE%.*};

Antwoord 23

Gebouw van Peteshantwoord, als alleen de bestandsnaam nodig is,
zowel pad als extensie kunnen in een enkele regel worden verwijderd,

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

Antwoord 24

Voornamelijk gebaseerd op @mklement0’s uitstekende, en boordevol willekeurige, nuttige bashisms– evenals andere antwoorden op deze / andere vragen / “dat verdomde internet”… Ik heb het ingepakt alles in een kleine, iets meer begrijpelijke, herbruikbare functievoor mijn (of uw) .bash_profiledie zorgt voor wat (naar mijn mening) een robuustere versie van zou moeten zijn dirname/basename/ wat heb je..

function path { SAVEIFS=$IFS; IFS=""   # stash IFS for safe-keeping, etc.
    [[ $# != 2 ]] && echo "usage: path <path> <dir|name|fullname|ext>" && return    # demand 2 arguments
    [[ $1 =~ ^(.*/)?(.+)?$ ]] && {     # regex parse the path
        dir=${BASH_REMATCH[1]}
        file=${BASH_REMATCH[2]}
        ext=$([[ $file = *.* ]] && printf %s ${file##*.} || printf '')
        # edge cases for extensionless files and files like ".nesh_profile.coffee"
        [[ $file == $ext ]] && fnr=$file && ext='' || fnr=${file:0:$((${#file}-${#ext}))}
        case "$2" in
             dir) echo      "${dir%/*}"; ;;
            name) echo      "${fnr%.*}"; ;;
        fullname) echo "${fnr%.*}.$ext"; ;;
             ext) echo           "$ext"; ;;
        esac
    }
    IFS=$SAVEIFS
}     

Gebruiksvoorbeelden…

SOMEPATH=/path/to.some/.random\ file.gzip
path $SOMEPATH dir        # /path/to.some
path $SOMEPATH name       # .random file
path $SOMEPATH ext        # gzip
path $SOMEPATH fullname   # .random file.gzip                     
path gobbledygook         # usage: -bash <path> <dir|name|fullname|ext>

Antwoord 25

Een eenvoudig antwoord:

Uit te breiden op de POSIX-variabelenantwoord, merk op dat u interessantere patronen kunt maken. Dus voor het geval dat hier wordt beschreven, kunt u eenvoudig dit doen:

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

Dat zal de laatste keer dat .tar.<iets>voorkomt, worden afgebroken.

Meer in het algemeen, als u het laatste exemplaar van .<something>.<something-else>wilt verwijderen, dan

${1.*.*}

zou goed moeten werken.

De link naar het bovenstaande antwoord lijkt dood te zijn. Hier is een geweldige uitleg van een aantal stringmanipulaties die je rechtstreeks in Bash kunt doen , van TLDP.


Antwoord 26

Als je ook legeextensies wilt toestaan, is dit de kortste die ik kon bedenken:

echo 'hello.txt' | sed -r 's/.+\.(.+)|.*/\1/' # EXTENSION
echo 'hello.txt' | sed -r 's/(.+)\..+|(.*)/\1\2/' # FILENAME

1e regel uitgelegd: het komt overeen met PATH.EXT of ANYTHING en vervangt het door EXT. Als er IETS is gevonden, wordt de ext-groep niet vastgelegd.


Antwoord 27

Dit is de enige die voor mij werkte:

path='folder/other_folder/file.js'
base=${path##*/}
echo ${base%.*}
>> file

Dit kan ook worden gebruikt bij string-interpolatie, maar helaas moet je vooraf baseinstellen.


Antwoord 28

Hier is het algoritme dat ik heb gebruikt om de naam en extensie van een bestand te vinden toen ik een Bash-script schreef om namen uniek te maken wanneer namen in strijd waren met de hoofdletters.

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

De testrun.

$ 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=
$ 

Ter info: het volledige transliteratieprogramma en meer testcases zijn hier te vinden:
https://www.dropbox.com/s/4c6m0f2e28a1vxf /avoid-clashes-code.zip?dl=0


Antwoord 29

Gebruik voorbeeldbestand /Users/Jonathan/Scripts/bash/MyScript.sh, deze code:

MY_EXT=".${0##*.}"
ME=$(/usr/bin/basename "${0}" "${MY_EXT}")

zal resulteren in ${ME}als MyScripten ${MY_EXT}als .sh:


Script:

#!/bin/bash
set -e
MY_EXT=".${0##*.}"
ME=$(/usr/bin/basename "${0}" "${MY_EXT}")
echo "${ME} - ${MY_EXT}"

Enkele tests:

$ ./MyScript.sh 
MyScript - .sh
$ bash MyScript.sh
MyScript - .sh
$ /Users/Jonathan/Scripts/bash/MyScript.sh
MyScript - .sh
$ bash /Users/Jonathan/Scripts/bash/MyScript.sh
MyScript - .sh

Antwoord 30

Van de bovenstaande antwoorden, de kortste oneliner om Python’s na te bootsen

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

ervan uitgaande dat uw bestand echt een extensie heeft, is

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

Other episodes