Hoe krijg ik de bestandsextensie van bash? Dit is wat ik heb geprobeerd:
filename=`basename $filepath` fileext=${filename##*.}
Door dat te doen kan ik de extensie bz2
krijgen van het pad /dir/subdir/file.bz2
, maar ik heb een probleem met het pad /dir/subdir/file-1.0.tar.bz2
.
Ik heb liever een oplossing met alleen bash zonder externe programmas als het mogelijk is.
Om mijn vraag duidelijk te maken, was ik een bash-script aan het maken om een bepaald archief uit te pakken met slechts een enkele opdracht van extract path_to_file
. het uitpakken van het bestand wordt bepaald door het script door het compressie- of archiveringstype te zien, dat kan .tar.gz, .gz, .bz2 etc. zijn. Ik denk dat dit stringmanipulatie zou moeten inhouden, bijvoorbeeld als ik de extensie .gz
, dan moet ik controleren of er de tekenreeks .tar
voor .gz
staat – als dit het geval is, moet de extensie be .tar.gz
.
Reacties
- file = ” /dir/subdir/file-1.0.tar.bz2
; echo $ {file ## *.} drukt ‘ .bz2 ‘ hier af. Wat is de output die u ‘ verwacht?
.tar.bz2
Antwoord
Als de bestandsnaam file-1.0.tar.bz2
is, is de extensie bz2
. De methode die u gebruikt om de extensie te extraheren (fileext=${filename##*.}
) is volkomen geldig¹.
Hoe besluit u dat u de extensie tar.bz2
en niet bz2
of 0.tar.bz2
? U moet deze vraag eerst beantwoorden. Vervolgens kunt u uitzoeken wat shell-commando komt overeen met uw specificatie.
-
Een mogelijke specificatie is dat extensies met een letter moeten beginnen. Deze heuristiek mislukt voor een paar veelvoorkomende extensies zoals
7z
, wat misschien het beste kan worden behandeld als een speciaal geval. Hier “sa bash / ksh / zsh implementatie:basename=$filename; fileext= while [[ $basename = ?*.* && ( ${basename##*.} = [A-Za-z]* || ${basename##*.} = 7z ) ]] do fileext=${basename##*.}.$fileext basename=${basename%.*} done fileext=${fileext%.}
Voor POSIX-draagbaarheid moet u een
case
-instructie voor patroonvergelijking.while case $basename in ?*.*) case ${basename##*.} in [A-Za-z]*|7z) true;; *) false;; esac;; *) false;; esac do …
-
Een andere mogelijke specificatie is dat sommige extensies duiden coderingen aan en geven aan dat verder strippen nodig is. Hier “sa bash / ksh / zsh implementatie (vereist
shopt -s extglob
onder bash ensetopt ksh_glob
onder zsh):basename=$filename fileext= while [[ $basename = ?*.@(bz2|gz|lzma) ]]; do fileext=${basename##*.}.$fileext basename=${basename%.*} done if [[ $basename = ?*.* ]]; then fileext=${basename##*.}.$fileext basename=${basename%.*} fi fileext=${fileext%.}
Merk op dat dit
0
beschouwt als een extensie infile-1.0.gz
.
¹ ${VARIABLE##SUFFIX}
en gerelateerde constructies bevinden zich in POSIX , dus ze werken in elke niet-antieke Bourne-stijl shell, zoals ash, bash, ksh of zsh.
Reacties
- dat zou moeten worden opgelost door te controleren of de tekenreeks vóór de laatste
.
-token het archieftype is, bijvoorbeeldtar
, als het geen archieftype is zoals0
iteratie zou moeten eindigen. - @uray: dat werkt in dit specifieke geval, maar het ‘ is geen algemene oplossing . Overweeg Maciej ‘ s voorbeeld van
.patch.lzma
. Een betere heur istic zou zijn om de string na de laatste.
te beschouwen: als het ‘ een compressie-achtervoegsel is (.7z
,.bz2
,.gz
, …), ga verder met strippen. - @NoamM Wat was er mis met de inspringing? Het ‘ is definitief verbroken na je bewerking: dubbel geneste code springt hetzelfde in als enkelvoudig genest.
Antwoord
Je zou zaken kunnen vereenvoudigen door gewoon patroonvergelijking op de bestandsnaam uit te voeren in plaats van de extensie twee keer te extraheren:
case "$filename" in *.tar.bz2) bunzip_then_untar ;; *.bz2) bunzip_only ;; *.tar.gz) untar_with -z ;; *.tgz) untar_with -z ;; *.gz) gunzip_only ;; *.zip) unzip ;; *.7z) do something ;; *) do nothing ;; esac
Reacties
- Deze oplossing is prachtig eenvoudig.
Antwoord
$ echo "thisfile.txt"|awk -F . "{print $NF}"
Reageert hier op: http://liquidat.wordpress.com/2007/09/29/short-tip-get-file-extension-in-shell-script/
Reacties
- werkt niet voor
.tar.gz
extensie - Nou een .tar .gz is eigenlijk een tar in een gzip-bestand, dus het werkt in die zin dat het een gz-extensie uit een gzip-bestand verwijdert.
Antwoord
Hier is mijn kans: punten naar nieuwe regels vertalen, door tail
, haal laatste regel op:
$> TEXT=123.234.345.456.456.567.678 $> echo $TEXT | tr . \\n | tail -n1 678
Antwoord
Op een dag heb ik “die lastige functies gemaakt:
# args: string how_many function get_last_letters(){ echo ${1:${#1}-$2:$2}; } function cut_last_letters(){ echo ${1:0:${#1}-$2}; }
Ik heb deze eenvoudige benadering gevonden, die in veel gevallen erg nuttig is, niet alleen als het gaat over extensies.
Voor het controleren van extensies – Het is eenvoudig en betrouwbaar
~$ get_last_letters file.bz2 4 .bz2 ~$ get_last_letters file.0.tar.bz2 4 .bz2
Voor het afsnijden van extensie:
~$ cut_last_letters file.0.tar.bz2 4 file.0.tar
Voor het wijzigen van extensie:
~$ echo $(cut_last_letters file.0.tar.bz2 4).gz file.0.tar.gz
Of, als je houdt van “handige functies:
~$ function cut_last_letters_and_add(){ echo ${1:0:${#1}-$2}"$3"; } ~$ cut_last_letters_and_add file.0.tar.bz2 4 .gz file.0.tar.gz
PS Als je die functies leuk vond of ze gebruikt vond, verwijs alstublieft naar dit bericht 🙂 (en hopelijk plaats een opmerking).
Antwoord
echo ${filename#$(echo $filename | sed "s/\.[^[:digit:]].*$//g;")}
Bijvoorbeeld:
Reacties
- Werkt niet in alle gevallen. Probeer met ‘ foo.7z ‘
- Je hebt aanhalingstekens nodig, en beter
printf
als de bestandsnaam een backslash bevat of begint met-
:"${filename#$(printf %s "$filename" | sed 's/\.[^[:digit:]].*$//g;')}"
- @axel_c : right, en ik ‘ heb dezelfde specificatie geïmplementeerd als Maciej als voorbeeld. Welke heuristiek suggereert u dat ‘ beter is dan “begint met een letter”?
- @Gilles: ik denk dat er ‘ is geen oplossing tenzij u een vooraf berekende lijst met bekende extensies gebruikt, omdat een extensie van alles kan zijn.
Antwoord
het Jackman case-based antwoord is redelijk goed en draagbaar, maar als je alleen de bestandsnaam en extensie in een variabele wilt hebben, heb ik deze oplossing gevonden:
INPUTFILE="$1" INPUTFILEEXT=$( echo -n "$INPUTFILE" | rev | cut -d"." -f1 | rev ) INPUTFILEEXT=$( echo -n $INPUTFILEEXT | tr "[A-Z]" "[a-z]" ) # force lowercase extension INPUTFILENAME="`echo -n \"$INPUTFILE\" | rev | cut -d"." -f2- | rev`" # fix for files with multiple extensions like "gbamidi-v1.0.tar.gz" INPUTFILEEXT2=$( echo -n "$INPUTFILENAME" | rev | cut -d"." -f1 | rev ) if [ "$INPUTFILEEXT2" = "tar" ]; then # concatenate the extension INPUTFILEEXT="$INPUTFILEEXT2.$INPUTFILEEXT" # update the filename INPUTFILENAME="`echo -n \"$INPUTFILENAME\" | rev | cut -d"." -f2- | rev`" fi
Het werkt alleen met dubbele extensies en de eerste moet “tar” zijn.
Maar je kunt de “tar” -testregel wijzigen met een stringlengtetest en de reparatie meerdere keren herhalen .
Antwoord
ik heb het opgelost door dit te gebruiken:
filename=`basename $filepath` fileext=${filename##*.} fileext2=${filename%.*} fileext3=${fileext2##*.} if [ "$fileext3" == "tar" ]; then fileext="tar."$fileext fi
maar dit werkt alleen voor bekende archiveringstypes, in dit geval alleen tar