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 ‚?
.tar.bz2
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 asetopt 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 vfile-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říkladtar
, pokud nejde o typ archivu jako0
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