Kuinka saan tiedostopääte bashilta? Tässä yritin:
filename=`basename $filepath` fileext=${filename##*.}
Tällöin saan bz2
-laajennuksen polulta /dir/subdir/file.bz2
, mutta minulla on ongelma polulla /dir/subdir/file-1.0.tar.bz2
.
Haluaisin mieluummin ratkaisun, jossa käytetään vain bash-tiedostoa ilman ulkoista ohjelmia, jos se on mahdollista.
Kysymykseni selventämiseksi luoin bash-komentosarjan, jolla jokin arkisto purettiin vain yhdellä komennolla extract path_to_file
. tiedoston purkaminen määritetään komentosarjan avulla näkemällä sen pakkaus- tai arkistointityyppi, joka voi olla .tar.gz, .gz, .bz2 jne. Mielestäni tämän pitäisi liittyä merkkijonon manipulointiin, esimerkiksi jos saan laajennuksen .gz
minun pitäisi tarkistaa, onko siinä merkkijono .tar
ennen .gz
– jos on, laajennuksen tulisi olla be .tar.gz
.
Kommentit
- file = ” /dir/subdir/file-1.0.tar.bz2
; echo $ {file ## *.} tulostaa ’ .bz2 ’ tänne. Mikä on tulos, jonka ’ odotat uudelleen?
.tar.bz2
Vastaa
Jos tiedoston nimi on file-1.0.tar.bz2
, laajennus on bz2
. Menetelmä, jota käytät laajennuksen purkamiseen (fileext=${filename##*.}
), on täysin kelvollinen¹.
Kuinka päätät laajennuksen olevan tar.bz2
eikä bz2
tai 0.tar.bz2
? Sinun on ensin vastattava tähän kysymykseen. Sitten voit selvittää, mitä shell-komento vastaa määritystesi.
-
Yksi mahdollinen määrittely on, että laajennusten on aloitettava kirjaimella. Tämä heuristinen tiedosto epäonnistuu muutamalle yleiselle laajennukselle, kuten
7z
, jota voidaan parhaiten käsitellä erityistapauksena. Tässä ”bash / ksh / zsh-toteutus:basename=$filename; fileext= while [[ $basename = ?*.* && ( ${basename##*.} = [A-Za-z]* || ${basename##*.} = 7z ) ]] do fileext=${basename##*.}.$fileext basename=${basename%.*} done fileext=${fileext%.}
POSIX-siirrettävyys edellyttää, että
case
-lauseke mallien sovittamiseksi.while case $basename in ?*.*) case ${basename##*.} in [A-Za-z]*|7z) true;; *) false;; esac;; *) false;; esac do …
-
Toinen mahdollinen erittely on, että jotkut Laajennukset merkitsevät koodauksia ja osoittavat, että tarvitaan lisää strippauksia. Tässä ”sa bash / ksh / zsh -toteutus (vaatii
shopt -s extglob
bashin alla jasetopt ksh_glob
zsh: n alla):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%.}
Huomaa, että tämä pitää
0
laajennuksena tiedostossafile-1.0.gz
.
¹ ${VARIABLE##SUFFIX}
ja siihen liittyvät rakenteet ovat POSIXissa , joten he työskentelevät missä tahansa muussa kuin antiikkisessa Bourne-tyylisessä kuoressa, kuten tuhka, bash, ksh tai zsh.
Kommentit
- joiden pitäisi ratkaistaan tarkistamalla, onko merkkijono edellisen
.
-tunnisteen tyyppi on arkistotyyppi, esimerkiksitar
, jos se ei ole arkistotyyppi kuten0
iteroinnin pitäisi päättyä. - @uray: se toimii tässä nimenomaisessa tapauksessa, mutta se ’ ei ole yleinen ratkaisu Harkitse Maciej ’ esimerkkiä
.patch.lzma
. Parempi heur istic olisi harkita merkkijonoa viimeisen.
-merkin jälkeen: jos se ’ sa-pakkausliite (.7z
,.bz2
,.gz
, …), jatka strippaamista. - @NoamM Mikä oli vikaa sisennyksessä? Se ’ rikkoo ehdottomasti muokkauksesi jälkeen: kaksinkertaisesti sisäkkäinen koodi on sisennys sama kuin yksitellen sisäkkäinen.
Vastaa
Voit yksinkertaistaa asioita tekemällä pelkän mallin vastaavuuden tiedostonimelle sen sijaan, että purat laajennuksen kahdesti:
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
Kommentit
- Tämä ratkaisu on kauniisti yksinkertainen.
Vastaa
$ echo "thisfile.txt"|awk -F . "{print $NF}"
Kommentteja tähän: http://liquidat.wordpress.com/2007/09/29/short-tip-get-file-extension-in-shell-script/
kommentit
- ei toimi
.tar.gz
-laajennuksella - No .tar .gz on oikeastaan terva gzip-tiedoston sisällä, joten se toimii siinä mielessä, että se poistaa gz-laajennuksen gzip-tiedostosta.
Vastaa
Tässä on minun laukaukseni: Käännä pisteet uudelle riville, vie tail
, hae viimeinen rivi:
$> TEXT=123.234.345.456.456.567.678 $> echo $TEXT | tr . \\n | tail -n1 678
vastaus
Eräänä päivänä olen luonut nuo hankalat toiminnot:
# args: string how_many function get_last_letters(){ echo ${1:${#1}-$2:$2}; } function cut_last_letters(){ echo ${1:0:${#1}-$2}; }
Olen havainnut tämän suoraviivan lähestymistavan, joka on erittäin hyödyllinen monissa tapauksissa, ei vain silloin, kun se käy Tietoja laajennuksista.
Laajennusten tarkistamiseen – Se on yksinkertainen ja luotettava
~$ get_last_letters file.bz2 4 .bz2 ~$ get_last_letters file.0.tar.bz2 4 .bz2
Laajennuksen katkaisu:
~$ cut_last_letters file.0.tar.bz2 4 file.0.tar
Laajennuksen muuttaminen:
~$ echo $(cut_last_letters file.0.tar.bz2 4).gz file.0.tar.gz
Tai jos haluat ”käteviä toimintoja:
~$ 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 Jos pidit näistä funktioista tai pidit niitä hyödyllisinä, katso tämä viesti 🙂 (ja toivottavasti lisää kommentti).
Vastaa
echo ${filename#$(echo $filename | sed "s/\.[^[:digit:]].*$//g;")}
Esimerkiksi:
Kommentit
- Ei toimi kaikissa tapauksissa. Kokeile ’ foo.7z ’
- Tarvitset lainausmerkkejä ja käytä paremmin
printf
jos tiedostonimi sisältää taaksepäin viivan tai alkaa-
:"${filename#$(printf %s "$filename" | sed 's/\.[^[:digit:]].*$//g;')}"
- @axel_c : oikea, ja olen ’ toteuttanut saman spesifikaation kuin Maciej esimerkkinä. Mitä heuristista ehdotat, että ’ on parempi kuin ”alkaa kirjaimella”?
- @Gilles: Luulen vain, että ’ ei ole ratkaisu, ellet käytä ennalta laskettua luetteloa tunnetuista laajennuksista, koska laajennus voi olla mikä tahansa.
Vastaa
jackmanin tapauskohtainen vastaus on melko hyvä ja kannettava, mutta jos haluat vain tiedostonimen ja laajennuksen muuttujaan, olen löytänyt tämän ratkaisun:
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
Se toimii vain kaksoislaajennuksilla ja ensimmäisen on oltava ”terva”.
Mutta voit vaihtaa ”terva” -testirivin merkkijonotestillä ja toistaa korjauksen useita kertoja .
vastaus
olen ratkaissut sen tällä tavalla:
filename=`basename $filepath` fileext=${filename##*.} fileext2=${filename%.*} fileext3=${fileext2##*.} if [ "$fileext3" == "tar" ]; then fileext="tar."$fileext fi
mutta tämä toimii vain tunnetulle arkistointityypille, tässä tapauksessa vain tar