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?
.tar.bz2
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 éssetopt 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 azfile-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áultar
, ha nem olyan archív típusú, mint a0
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