Hvordan får jeg filtypen fra bash? Her er det jeg prøvde:
filename=`basename $filepath` fileext=${filename##*.}
Ved å gjøre det kan jeg få utvidelse av bz2
fra banen /dir/subdir/file.bz2
, men jeg har et problem med banen /dir/subdir/file-1.0.tar.bz2
.
Jeg foretrekker en løsning som bare bruker bash uten ekstern programmer hvis det er mulig.
For å gjøre spørsmålet mitt klart, opprettet jeg et bash-skript for å trekke ut et gitt arkiv bare ved en enkelt kommando på extract path_to_file
. for å trekke ut filen bestemmes av skriptet ved å se komprimering eller arkiveringstype, som kan være .tar.gz, .gz, .bz2 osv. Jeg tror dette burde innebære strengmanipulering, for eksempel hvis jeg får utvidelsen .gz
så bør jeg sjekke om den har strengen .tar
før .gz
– i så fall bør utvidelsen være .tar.gz
.
Kommentarer
- file = » /dir/subdir/file-1.0.tar.bz2
; ekko $ {file ## *.} skriver ut ‘ .bz2 ‘ her. Hva er utgangen du ‘ forventer?
.tar.bz2
Svar
Hvis filnavnet er file-1.0.tar.bz2
, er utvidelsen bz2
. Metoden du bruker for å trekke ut utvidelsen (fileext=${filename##*.}
) er helt gyldig¹.
Hvordan bestemmer du at du vil at utvidelsen skal være tar.bz2
og ikke bz2
eller 0.tar.bz2
? Du må svare på dette spørsmålet først. Så kan du finne ut hva skallkommando samsvarer med spesifikasjonen din.
-
En mulig spesifikasjon er at utvidelser må begynne med en bokstav. Denne heuristikken mislykkes for noen få vanlige utvidelser som
7z
, som best kan behandles som et spesielt tilfelle. Her «sa bash / ksh / zsh implementering:basename=$filename; fileext= while [[ $basename = ?*.* && ( ${basename##*.} = [A-Za-z]* || ${basename##*.} = 7z ) ]] do fileext=${basename##*.}.$fileext basename=${basename%.*} done fileext=${fileext%.}
For POSIX-portabilitet, må du bruke en
case
uttalelse for mønstermatching.while case $basename in ?*.*) case ${basename##*.} in [A-Za-z]*|7z) true;; *) false;; esac;; *) false;; esac do …
-
En annen mulig spesifikasjon er at noen utvidelser angir kodinger og indikerer at det er behov for videre stripping. Her «sa bash / ksh / zsh implementering (krever
shopt -s extglob
under bash ogsetopt ksh_glob
under 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 at dette anser
0
for å være en utvidelse ifile-1.0.gz
.
¹ ${VARIABLE##SUFFIX}
og relaterte konstruksjoner er i POSIX , så de fungerer i et ikke-antikt Bourne-stil skall som ask, bash, ksh eller zsh.
Kommentarer
- løses ved å sjekke om strengen før siste
.
token er arkivtype, for eksempeltar
, hvis det ikke er arkivtype som0
iterasjonen skal avsluttes. - @uray: det fungerer i dette tilfellet, men det ‘ er ikke en generell løsning Tenk på Maciej ‘ s eksempel på
.patch.lzma
. En bedre heur istisk ville være å ta i betraktning strengen etter den siste.
: hvis den ‘ er et kompresjonssuffiks (.7z
,.bz2
,.gz
, …), fortsett å strippe. - @NoamM Hva var galt med fordypningen? Den ‘ er definitivt ødelagt etter redigeringen din: Dobbelt nestet kode er innrykket den samme som enkelt nestet.
Svar
Du kan forenkle ting ved å bare gjøre mønstermatching på filnavnet i stedet for å trekke ut utvidelsen to ganger:
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
Kommentarer
- Denne løsningen er vakkert enkel.
Svar
$ echo "thisfile.txt"|awk -F . "{print $NF}"
Kommentarer til dette her: http://liquidat.wordpress.com/2007/09/29/short-tip-get-file-extension-in-shell-script/
Kommentarer
- fungerer ikke for
.tar.gz
utvidelse - Vel en .tar .gz er faktisk en tjære i en gzip-fil, så den fungerer i den forstand at den fjerner en gz-utvidelse fra en gzip-fil.
Svar
Her er skuddet mitt: Oversett prikker til nye linjer, rør gjennom tail
, få siste linje:
$> TEXT=123.234.345.456.456.567.678 $> echo $TEXT | tr . \\n | tail -n1 678
Svar
En dag har jeg opprettet de vanskelige funksjonene:
# args: string how_many function get_last_letters(){ echo ${1:${#1}-$2:$2}; } function cut_last_letters(){ echo ${1:0:${#1}-$2}; }
Jeg har funnet denne greie tilnærmingen, veldig nyttig i mange tilfeller, ikke bare når det går om utvidelser.
For å sjekke utvidelser – Det er enkelt og pålitelig
~$ get_last_letters file.bz2 4 .bz2 ~$ get_last_letters file.0.tar.bz2 4 .bz2
For avskjæring av utvidelse:
~$ cut_last_letters file.0.tar.bz2 4 file.0.tar
For endring av utvidelse:
~$ echo $(cut_last_letters file.0.tar.bz2 4).gz file.0.tar.gz
Eller hvis du liker «praktiske funksjoner:
~$ 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 Hvis du likte disse funksjonene eller fant dem brukt, referer til dette innlegget 🙂 (og forhåpentligvis legg en kommentar).
Svar
echo ${filename#$(echo $filename | sed "s/\.[^[:digit:]].*$//g;")}
For eksempel:
Kommentarer
- Fungerer ikke i alle tilfeller. Prøv med ‘ foo.7z ‘
- Du trenger tilbud, og bedre bruk
printf
hvis filnavnet inneholder en tilbakeslag eller begynner med-
:"${filename#$(printf %s "$filename" | sed 's/\.[^[:digit:]].*$//g;')}"
- @axel_c : right, og jeg ‘ har implementert samme spesifikasjon som Maciej som et eksempel. Hvilken heuristisk antyder du at ‘ er bedre enn “begynner med en bokstav”?
- @Gilles: jeg tror bare det ‘ er ikke en løsning med mindre du bruker en forhåndsberegnet liste over kjente utvidelser, fordi en utvidelse kan være hva som helst.
Svar
det jackman-saksbaserte svaret er ganske bra og bærbart, men hvis du bare vil ha filnavnet og utvidelsen i en variabel, har jeg funnet denne løsningen:
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
Det fungerer bare med doble utvidelser, og den første må være «tjære».
Men du kan endre «tjære» testlinjen med en strenglengdetest og gjenta fiksen flere ganger .
Svar
jeg løste det ved hjelp av dette:
filename=`basename $filepath` fileext=${filename##*.} fileext2=${filename%.*} fileext3=${fileext2##*.} if [ "$fileext3" == "tar" ]; then fileext="tar."$fileext fi
men dette fungerer bare for kjent arkiveringstype, i dette tilfellet bare tar