bash: hoe retourneer je bestandsextensies?

Ik wil een script schrijven om alleen de extensie van de invoerbestandsnaam te retourneren. textfile.txt zou bijvoorbeeld txt moeten retourneren.

Ik ben nieuw bij Linux en bash, en ik “m proberen te leren basisscripts te schrijven. Bedankt!

Reacties

  • Zie ook stackoverflow.com/questions/965053/…
  • Wat is de extensie van het linux-4.2.3.tar.xz -bestand dat u kunt downloaden van kernel.org ? Wat is de extensie van het /bin/bash -bestand dat zeker op uw systeem beschikbaar is? Zie je, het concept van ” bestandsextensie ” is nogal vreemd in Linux. Het gedeelte na de punt heeft weinig betekenis voor het systeem – het is eerder een indicatie voor de gebruiker over wat hij van dat bestand mag verwachten. En dat signaal kan liegen of verkeerd zijn.

Answer

De shell, bash bijvoorbeeld, heeft veel stringmanipulatie functies. Met een ervan kun je alles verwijderen tot een bepaald patroon:

${VAR##GLOB} 

De bovenstaande syntaxis verwijdert alles van de variabele $VAR tot de eerste overeenkomst van de glob GLOB. Dus om de extensie van een bestand zonder de naam af te drukken, zou je het volgende kunnen doen:

$ file="file.txt" $ echo ${file##*.} txt 

Merk op dat dit ook met meer dan één “extensie” kan omgaan:

$ file="file.new.txt" $ echo ${file##*.} txt 

Als je dat niet wilt, gebruik dan een #, die in plaats daarvan de kortste overeenkomst verwijdert of the longest:

$ echo ${file#*.} new.txt 

Om dit nu op alle bestanden in een directory uit te voeren, zou je het volgende kunnen doen:

$ ls file.avi file.pdf file.png file.txt $ for file in *; do echo "$file : ${file##*.}"; done file.avi : avi file.pdf : pdf file.png : png file.txt : txt 

En voor de volledigheid kunt u de bestandsnaam ook zonder de extensie krijgen met ${file%.*}:

$ for file in *; do echo "$file : ${file##*.} : ${file%.*}"; done file.avi : avi : file file.pdf : pdf : file file.png : png : file file.txt : txt : file 

Reacties

  • dit werkt niet ‘ niet voor zaken als foo / .git / bar / baz Ik denk dat je echo test.txt | zou kunnen doen awk -F ‘ / ‘ ‘ {print $ NF} ‘ | awk -F ‘. ‘ ‘ {print $ NF} ‘
  • @PaulM wat bedoel je? Dat ‘ sa-bestand zonder extensie, wat zou je daarvan verwachten?
  • echo ” / foo /var/.git/foo/bar.bz” | awk -F ‘ / ‘ ‘ {print $ NF} ‘ | awk -F ‘. ‘ ‘ {print $ NF} ‘ == > > bz
  • @PaulM file="/foo/var/.git/foo/bar.bz"; echo "${file##*.}": bz. Ik ‘ zie geen probleem.

Antwoord

Met parameteruitbreiding :

$ x="textfile.txt" $ echo ${x##*.} txt 

De ${parameter##word} patroon verwijdert het grootste voorvoegsel dat overeenkomt met word (alles behalve de bestandseinde).

Antwoord

Een heel eenvoudig bash-script dat zou kunnen doen wat je wilt, zou het volgende zijn:

#!/usr/bin/env bash echo "$1" | awk -F "." "{print $NF}" 

Het script wordt aangeroepen als script.sh test.txt, en wat het doet is

  • het drukt $1 naar stdout. $1 is de eerste parameter die aan het script wordt gegeven, in dit geval test.txt.

  • de standaarduitvoer van echo wordt doorgesluisd naar stdin voor awk die de string splitst (test.txt) op . en dan wordt het laatste element van de splitsing afgedrukt (txt in dit geval).

Gewoon een kleine opmerking, dit kan gedaan worden met een oneliner omdat het “een vrij simpele taak is:

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

Opmerkingen

  • U moet aanhalingstekens plaatsen rond $1, anders riskeert u bestandsnamen die spaties bevatten enz. te breken.
  • dit werkt niet ‘ t werkt voor zaken als foo / .git / bar / baz Ik denk dat je echo test.txt | awk -F ‘ / ‘ ‘ {print $ NF} ‘ | awk -F ‘.’ ‘ {print $ NF} ‘

Antwoord

#!/bin/bash my_file=`basename "$1"` # get full file name as a script parameter and strip the path my_extension="${my_file##*.}" my_file="${my_file%.*}" # will return base file name before the extension echo "$my_file" echo "$my_extension" 

Uitvoeren:

./script.sh index.html 

Uitvoer:

index html 

Meer info: Shell Parameter Expansion | gnu.org

Answer

Om dit te doen, zijn er verschillende kanttekeningen waarmee u rekening moet houden:

  • Het foo.d/bar -bestand heeft geen extensie, het is “geen foo -bestand met een .d/bar extensie.
  • Je kunt ook overwegen dat .bashrc geen extensie heeft
  • De . en .. speciale mapbestanden moeten waarschijnlijk speciaal worden behandeld en als geen enkele extensie worden beschouwd.
  • waarvoor is de extensie? file.tar.gz? gz of tar.gz? Hoe zit het met holiday.picture.jpg of bash-4.4?
  • Wat moet je retourneren voor foo.d/? Leeg of d?

Hier “zou ik doen:

#! /bin/sh - for file do case ${file##*/} in (?*.*) ext=${file##*.};; (*) ext=;; esac printf "%s\n" "$ext" done 

Opmerkingen

  • Uitstekende afhandeling van antwoorden, ook de gebruikelijke kanttekeningen en nuttige code, vooral als functie.

Antwoord

Ik “zal wat meer opties toevoegen voor het geval je sed of Perl hebt geïnstalleerd:

 #!/bin/bash ext=$(<<<"$1" sed -n "s/^[^.]*\.//p") printf "Extension: $ext\n" ext=$(<<<"$1" perl -ne "s/^.*?\.//&&print") printf "Extension: $ext\n" exit 0  
  • s/^[^.]*\.//p in sed en s/^.*?\.//&&print in perl: probeer de kortste reeks tekens te vervangen, niet . gevolgd door een . teken aan het begin van de string; als de vervanging kon worden gemaakt, druk dan het resultaat van de vervanging af;
 % bash script.sh file.bin Extension: bin Extension: bin  

Antwoord

Wees voorzichtig. In Unix / Linux (en MacOS) is de “bestandsnaamextensie” slechts informatief (als dat veel is). Je kunt perfect een Perl-script hebben met de naam photo.gif, of een GIF-bestand met de naam poem.txt. Of zelfs een bestand met de naam some.txt.png.

Reacties

  • Het ‘ is net zo informatief in MS Windows, het ‘ is alleen dat daarin het standaard shell-programma sterkere aannames doet over de koppeling tussen extensie en inhoud, en als er een mismatch tussen naamgeving en inhoud, het hele ding begint meestal gewoon fouten te schreeuwen, het arme ding.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *