De extensie in een bestandsnaam pakken

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?

  • ik heb .tar.bz2
  • Gerelateerd : Extraheer bestandsnaam en extensie in Bash .
  • 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 en setopt 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 in file-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, bijvoorbeeld tar, als het geen archieftype is zoals 0 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

    Geef een reactie

    Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *