A kiterjesztés megragadása egy fájlnévben

Hogyan szerezhetem a fájlkiterjesztést a bash-ból? Itt próbáltam:

filename=`basename $filepath` fileext=${filename##*.} 

Ezzel megszerezhetem a bz2 kiterjesztését az /dir/subdir/file.bz2, de problémám van az /dir/subdir/file-1.0.tar.bz2 útvonallal.

Szeretnék olyan megoldást használni, amely csak a bash-t használja külső nélkül programokat, ha lehetséges.

A kérdésem egyértelművé tétele érdekében létrehoztam egy bash szkriptet, amely az adott archívumot egyetlen extract path_to_file paranccsal bontja ki. A fájl kibontását a szkript határozza meg a tömörítés vagy az archiválás típusának megtekintésével. Ez lehet .tar.gz, .gz, .bz2 stb. Szerintem ennek sztringmanipulációt kell magában foglalnia, például ha a .gz, akkor ellenőriznem kell, hogy a .tar karakterlánc szerepel-e .gz előtt – ha igen, akkor a kiterjesztésnek be .tar.gz.

Megjegyzések

  • file = ” /dir/subdir/file-1.0.tar.bz2

; Az echo $ {file ## *.} itt kinyomtatja a ‘ .bz2 ‘ ikont. Mi az a kimenet, amelyre ‘ várt?

  • Szükségem van .tar.bz2
  • : Fájlnév és kiterjesztés kibontása a Bash fájlban .
  • Válasz

    Ha a fájl neve file-1.0.tar.bz2, a kiterjesztés bz2. A kiterjesztés kibontásához használt módszer (fileext=${filename##*.}) tökéletesen érvényes¹.

    Hogyan döntötte el, hogy a kiterjesztés tar.bz2 és nem bz2 vagy 0.tar.bz2? Először válaszoljon erre a kérdésre. Ezután megtudhatja, mi A shell parancs megfelel az Ön specifikációjának.

    • Az egyik lehetséges specifikáció az, hogy a kiterjesztéseknek betűvel kell kezdődniük. Ez a heurisztika néhány általános kiterjesztésnél, például 7z, amelyet a legjobban speciális esetként kezelhetünk. Itt a bash / ksh / zsh megvalósítás:

      basename=$filename; fileext= while [[ $basename = ?*.* && ( ${basename##*.} = [A-Za-z]* || ${basename##*.} = 7z ) ]] do fileext=${basename##*.}.$fileext basename=${basename%.*} done fileext=${fileext%.} 

      A POSIX hordozhatósághoz használnia kell case utasítás a mintaillesztéshez.

      while case $basename in ?*.*) case ${basename##*.} in [A-Za-z]*|7z) true;; *) false;; esac;; *) false;; esac do … 
    • Egy másik lehetséges specifikáció az, hogy néhány kiterjesztések jelölik a kódolásokat és jelzik, hogy további csíkokra van szükség. Itt “a bash / ksh / zsh megvalósítás (shopt -s extglob szükséges a bash alatt és setopt ksh_glob zsh alatt):

      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%.} 

      Ne feledje, hogy ez a 0 kiterjesztésnek tekinti az file-1.0.gz.

    ¹ ${VARIABLE##SUFFIX} és a kapcsolódó konstrukciók POSIX fájlban vannak, tehát bármilyen nem antik Bourne-stílusú héjban dolgoznak, például hamuban, bashban, ksh-ben vagy zsh-ben.

    Megjegyzések

    • lehet megoldani, ellenőrizve, hogy az utolsó . token előtti karakterlánc archív típusú-e, például tar, ha nem olyan archív típusú, mint a 0 iterációnak véget kell érnie.
    • @uray: ez ebben a konkrét esetben működik, de ‘ nem általános megoldás Tekintsük Maciej ‘ példáját a .patch.lzma -re. Az istic az lenne, ha az utolsó . karakterláncot figyelembe vennénk: ha ‘ sa tömörítési utótag (.7z, .bz2, .gz, …), folytassa a sztrippelést.
    • @NoamM Mi volt a baj a behúzással? ‘ a szerkesztés után határozottan megszakad: a duplán beágyazott kód ugyanúgy behúzódik, mint az egyenként beágyazott.

    Válasz

    Megkönnyítheti a helyzetet, ha csak a fájlnévminta-egyezést hajtja végre, nem pedig kétszer kibontja a kiterjesztést:

    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 

    Megjegyzések

    • Ez a megoldás gyönyörűen egyszerű.

    Válasz

    $ echo "thisfile.txt"|awk -F . "{print $NF}" 

    Erre vonatkozó megjegyzések itt találhatók: http://liquidat.wordpress.com/2007/09/29/short-tip-get-file-extension-in-shell-script/

    Megjegyzések

    • nem működnek a .tar.gz kiterjesztésnél
    • Nos .tar A .gz valójában egy tar a gzip fájlban, tehát abban az értelemben működik, hogy eltávolítja a gz kiterjesztést a gzip fájlból.

    Válasz

    Itt van a lövésem: Pontokat fordítson új sorokra, vezessen át tail, kapja meg az utolsó sort:

    $> TEXT=123.234.345.456.456.567.678 $> echo $TEXT | tr . \\n | tail -n1 678 

    Válasz

    Egy nap létrehoztam ezeket a trükkös funkciókat:

    # args: string how_many function get_last_letters(){ echo ${1:${#1}-$2:$2}; } function cut_last_letters(){ echo ${1:0:${#1}-$2}; } 

    Ezt az egyszerű megközelítést sok esetben nagyon hasznosnak találtam, nem csak akkor, amikor megy a bővítményekről.

    A kiterjesztések ellenőrzéséhez – Ez egyszerű és megbízható

    ~$ get_last_letters file.bz2 4 .bz2 ~$ get_last_letters file.0.tar.bz2 4 .bz2 

    A kiterjesztés levágásához:

    ~$ cut_last_letters file.0.tar.bz2 4 file.0.tar 

    A kiterjesztés módosításához:

    ~$ echo $(cut_last_letters file.0.tar.bz2 4).gz file.0.tar.gz 

    Vagy ha tetszik a “praktikus funkciók:

    ~$ 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 Ha tetszettek ezek a függvények, vagy hasznosnak találta, kérjük, olvassa el ezt a bejegyzést 🙂 (és remélhetőleg írjon megjegyzést).

    Válasz

    echo ${filename#$(echo $filename | sed "s/\.[^[:digit:]].*$//g;")} 

    Például:

    Megjegyzések

    • Nem minden esetben működik. Próbálja ki a következővel: ‘ foo.7z ‘
    • Idézetekre van szüksége, és jobban használja a printf abban az esetben, ha a fájlnév visszavonást tartalmaz, vagy - -vel kezdődik: "${filename#$(printf %s "$filename" | sed 's/\.[^[:digit:]].*$//g;')}"
    • @axel_c : right, és én ‘ ugyanazt a specifikációt valósítottam meg, mint Maciej. Milyen heurisztikát javasol arra, hogy ‘ jobb legyen, mint a „betűvel kezdődik”?
    • @Gilles: szerintem csak ‘ nem jelent megoldást, kivéve, ha az ismert kiterjesztések előre kiszámolt listáját használja, mert a kiterjesztés bármi lehet.

    Válasz

    a jackman eset alapú válasz nagyon jó és hordozható, de ha csak a fájlnevet és a kiterjesztést akarja egy változóba, akkor ezt a megoldást találtam:

    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 

    Csak dupla kiterjesztésekkel működik, és az elsőnek tarnak kell lennie.

    De a “tar” teszt sort módosíthatja egy string hosszúságú teszttel, és többször is megismételheti a javítást .

    Válasz

    ezt a következő módon oldottam meg:

    filename=`basename $filepath` fileext=${filename##*.} fileext2=${filename%.*} fileext3=${fileext2##*.} if [ "$fileext3" == "tar" ]; then fileext="tar."$fileext fi 

    de ez csak ismert archiválási típus esetén működik, ebben az esetben csak tar

    Vélemény, hozzászólás?

    Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük