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 a
en b.js
, in plaats van a.b
en 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:
- op het web in het gedeelte “3.5.3 Shell Parameter expansie “
- in de bash-manpage in sectie genaamd “Parameter Expansion”
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.gz
had, 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 NAME
vervangt 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 EXTENSION
vervangt 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 basename
gebruiken.
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 tar
uitvoert 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 awk
of sed
of 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)
zodatroot + 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 cut
kunnen 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 sed
te 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.
- Blind voorgaand
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.gz
is, 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 file
en man mime.types
. Misschien moet je de file
hulpprogramma en <mime-support
pakketten):
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 stuff
als bestandsnaam en .tar.gz
als 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_profile
die 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 base
instellen.
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 MyScript
en ${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)