Uchopení přípony v názvu souboru

Jak získám příponu souboru z bash? Zde je to, co jsem zkoušel:

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

Tímto způsobem mohu získat rozšíření bz2 z cesty /dir/subdir/file.bz2, ale mám problém s cestou /dir/subdir/file-1.0.tar.bz2.

Dávám přednost řešení používajícímu pouze bash bez externího programy, pokud je to možné.

Aby byla moje otázka jasná, vytvářel jsem bash skript pro extrahování libovolného daného archivu jediným příkazem extract path_to_file. Jak extrahovat soubor určuje skript tím, že vidí jeho kompresi nebo typ archivace, což může být .tar.gz, .gz, .bz2 atd. Myslím, že by to mělo zahrnovat manipulaci s řetězci, například pokud dostanu příponu .gz pak bych měl zkontrolovat, zda má řetězec .tar před .gz – pokud ano, měla by přípona be .tar.gz.

Komentáře

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

; echo $ {file ## *.} vytiskne ‚ .bz2 ‚ zde. Jaký výstup očekáváte ‚?

  • potřebuji .tar.bz2
  • : Extrahujte název souboru a příponu v Bash .
  • Odpovědět

    Pokud je název souboru file-1.0.tar.bz2, přípona je bz2. Metoda, kterou používáte k extrahování přípony (fileext=${filename##*.}), je naprosto platná.1.

    Jak se rozhodnete, že chcete, aby přípony byly tar.bz2 a ne bz2 nebo 0.tar.bz2? Nejprve musíte odpovědět na tuto otázku. Pak můžete zjistit, co příkaz shell odpovídá vaší specifikaci.

    • Jednou z možných specifikací je, že rozšíření musí začínat písmenem. Tato heuristika selže u několika běžných přípon, jako je 7z, se kterým lze nejlépe zacházet jako se zvláštním případem. Zde je implementace bash / ksh / zsh:

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

      Pro přenositelnost POSIX je třeba použít a case prohlášení o shodě vzorů.

      while case $basename in ?*.*) case ${basename##*.} in [A-Za-z]*|7z) true;; *) false;; esac;; *) false;; esac do … 
    • Další možnou specifikací je, že některé rozšíření označují kódování a označují, že je nutné další odizolování. Zde je implementace bash / ksh / zsh (vyžaduje shopt -s extglob pod bash a setopt ksh_glob pod 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%.} 

      Upozorňujeme, že toto považuje 0 za příponu v file-1.0.gz.

    ¹ ${VARIABLE##SUFFIX} a související konstrukty jsou v POSIX , takže fungují v jakémkoli starožitném prostředí Bourneova stylu, jako je ash, bash, ksh nebo zsh.

    Komentáře

    • které by měly bude vyřešeno kontrolou, zda je řetězec před posledním . tokenem typu archivu, například tar, pokud nejde o typ archivu jako 0 iterace by měla skončit.
    • @uray: to v tomto konkrétním případě funguje, ale ‚ nejde o obecné řešení . Zvažte Maciej ‚ příklad .patch.lzma . Lepší heur istic by bylo považovat řetězec za za poslední .: pokud je ‚ sa kompresní přípona (.7z, .bz2, .gz, …), pokračujte v odstraňování.
    • @NoamM Co se stalo s odsazením? Po vaší úpravě je to ‚ definitivně nefunkční: dvojnásobně vnořený kód je odsazen stejně jako jednotlivě vnořený.

    Odpovědět

    Záležitosti můžete zjednodušit pouhým provedením porovnávání vzorů v názvu souboru a nikoli extrahováním přípony dvakrát:

    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 

    Komentáře

    • Toto řešení je nádherně jednoduché.

    Odpověď

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

    Komentáře k tomu zde: http://liquidat.wordpress.com/2007/09/29/short-tip-get-file-extension-in-shell-script/

    Komentáře

    • nefunguje pro .tar.gz rozšíření
    • No .tar .gz je ve skutečnosti tar uvnitř souboru gzip, takže funguje v tom smyslu, že odstraní příponu gz ze souboru gzip.

    Odpověď

    Tady je můj záběr: Přeložit tečky na nové řádky, procházet tail, získat poslední řádek:

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

    odpověď

    Jednoho dne jsem vytvořil tyto záludné funkce:

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

    Tento přímý přístup mi připadá velmi užitečný, v mnoha případech, nejen když jde o rozšířeních.

    Pro kontrolu rozšíření – Je to jednoduché a spolehlivé

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

    Pro odříznutí rozšíření:

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

    Pro změnu rozšíření:

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

    Nebo, pokud máte rádi „užitečné funkce:

    ~$ 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 Pokud se vám tyto funkce líbily nebo vám připadaly užitečné, podívejte se prosím na tento příspěvek 🙂 (a doufejme, že přidáte komentář).

    Odpovědět

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

    Například:

    Komentáře

    • nefunguje u všech případů. Vyzkoušejte ‚ foo.7z ‚
    • potřebujete uvozovky a lépe použijte printf v případě, že název souboru obsahuje zpětné lomítko nebo začíná -: "${filename#$(printf %s "$filename" | sed 's/\.[^[:digit:]].*$//g;')}"
    • @axel_c : správně, a já ‚ implementoval stejnou specifikaci jako Maciej jako příklad. Jakou heuristiku naznačujete, že ‚ je lepší než „začíná písmenem“?
    • @Gilles: myslím si, že ‚ není řešením, pokud nepoužíváte předpočítaný seznam známých rozšíření, protože rozšíření může být cokoli.

    Odpovědět

    odpověď typu jackman na základě případů je docela dobrá a přenosná, ale pokud chcete pouze název souboru a příponu v proměnné, našel jsem toto řešení:

    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 

    Funguje pouze s dvojitými příponami a první musí být „tar“.

    Testovací řádek „tar“ však můžete změnit testem délky řetězce a opravu opakovat několikrát .

    Odpověď

    Vyřešil jsem to pomocí tohoto:

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

    ale toto funguje pouze pro známý typ archivace, v tomto případě pouze tar

    Napsat komentář

    Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *