Marx behöver inte mer hjälp
Marx 377
Postad: 26 nov 2021 23:20

Linux_hämta version

Jag har försökt på många sätt för att hämta Linuxversionen från lsb_release -a med hjälp av kommandot awk. Resultatet blir dock inte det jag strävar efter.

Skriver jag lsb_release -a blir outputen så här:

Hur ska jag göra om jag vill endast skriva ut "Ubuntu 21.10" med hjälp av awk-kommandot ?

Programmeraren 3390
Postad: 27 nov 2021 08:59 Redigerad: 27 nov 2021 09:21

Som alltid finns det otal olika sätt. awk är kraftfullt men å andra sidan kan man inte vara expert på alla kommandon i alla verktygsprogram. Ett relativt enkelt sätt att använda awk är att skriva program med C-syntax (åtminstone enkelt om man kan C eller Java). Det finns mer kompakta sätt som använder inbyggda funktioner i awk men jag har själv aldrig brytt mig om mer än några stycken.

Så här kan man göra med awk:

lsb_release -a 2>/dev/null|awk '{if ($1 == "Description:") { for(i=2;i<=NF;i++){printf("%s ", $i)} printf("\n")}}'

2>/dev/null är för att få bort fel/info som skrivs till stderr (t ex "No LSB modules are available")
Sen följer ett uttryck som ser ut ungefär som ett C-program.
$0 är hela raden, $1 är första fältet, $2 andra fältet osv. awk delar upp raden vid varje field separator, den är space som default (-F för att ändra)
NF är antal fält.
printf() medger formatering (ren "print $i" skriver ut radbryt också)

if ($1 == "Description:") {
	for (i=2; i<=NF; i++) {
		printf("%s ", $i)
	}
	printf("\n")
}

En ful detalj ovan är att ett extra space kommer skrivas ut sist på raden, det kan man undvika med en extra "if" som kolla om i+1<NF och då skriver space. Och det blev ganska långt.

Men vi kan använda att kolumnerna är separerade med tab:

lsb_release -a 2>/dev/null|awk -F '\t' '{if ($1 == "Description:") print $2}'

Mycket kompaktare och snyggare.

Om frågan vidgas så att man inte måste använda awk skulle min första tanke vara att använda grep och sed. Inte mer kompakt, bara ett exempel på att det finns många olika sätt att få fram det man vill ha: 

lsb_release -a 2>/dev/null|grep 'Description:'|sed 's/Description:\t//g'

grep väljer rätt rad
sed har en lika omfattande uppsättning möjligheter som awk men ska man kunna endast ett kommando är det "match and replace":
"s/MATCH/REPLACE/g"
MATCH: regex sed letar efter, här strängen "Description" följt av tab
REPLACE: vad vi ersätter med, här tomma strängen
g är "global", onödigt i detta fall men oftast vill man göra operationen på alla matchande ställen och inte bara på första i raden

Ovanstående kan förkortas till

lsb_release -a 2>/dev/null|grep 'Description'|sed 's/.*[\t]//g'

sed-uttrycket matchar nu "vad som helst" följt av tab

Marx 377
Postad: 27 nov 2021 12:58
Programmeraren skrev:

Som alltid finns det otal olika sätt. awk är kraftfullt men å andra sidan kan man inte vara expert på alla kommandon i alla verktygsprogram. Ett relativt enkelt sätt att använda awk är att skriva program med C-syntax (åtminstone enkelt om man kan C eller Java). Det finns mer kompakta sätt som använder inbyggda funktioner i awk men jag har själv aldrig brytt mig om mer än några stycken.

Så här kan man göra med awk:

lsb_release -a 2>/dev/null|awk '{if ($1 == "Description:") { for(i=2;i<=NF;i++){printf("%s ", $i)} printf("\n")}}'

2>/dev/null är för att få bort fel/info som skrivs till stderr (t ex "No LSB modules are available")
Sen följer ett uttryck som ser ut ungefär som ett C-program.
$0 är hela raden, $1 är första fältet, $2 andra fältet osv. awk delar upp raden vid varje field separator, den är space som default (-F för att ändra)
NF är antal fält.
printf() medger formatering (ren "print $i" skriver ut radbryt också)

if ($1 == "Description:") {
	for (i=2; i<=NF; i++) {
		printf("%s ", $i)
	}
	printf("\n")
}

En ful detalj ovan är att ett extra space kommer skrivas ut sist på raden, det kan man undvika med en extra "if" som kolla om i+1<NF och då skriver space. Och det blev ganska långt.

Men vi kan använda att kolumnerna är separerade med tab:

lsb_release -a 2>/dev/null|awk -F '\t' '{if ($1 == "Description:") print $2}'

Mycket kompaktare och snyggare.

Om frågan vidgas så att man inte måste använda awk skulle min första tanke vara att använda grep och sed. Inte mer kompakt, bara ett exempel på att det finns många olika sätt att få fram det man vill ha: 

lsb_release -a 2>/dev/null|grep 'Description:'|sed 's/Description:\t//g'

grep väljer rätt rad
sed har en lika omfattande uppsättning möjligheter som awk men ska man kunna endast ett kommando är det "match and replace":
"s/MATCH/REPLACE/g"
MATCH: regex sed letar efter, här strängen "Description" följt av tab
REPLACE: vad vi ersätter med, här tomma strängen
g är "global", onödigt i detta fall men oftast vill man göra operationen på alla matchande ställen och inte bara på första i raden

Ovanstående kan förkortas till

lsb_release -a 2>/dev/null|grep 'Description'|sed 's/.*[\t]//g'

sed-uttrycket matchar nu "vad som helst" följt av tab

Tack så mycket för dina lösningar och speciellt förklaringarna! Jag löste faktiskt själv problemet med något likt din andra lösning. Det som jag körde fast vid var field separatorn när det är tab.

Laguna Online 30721
Postad: 27 nov 2021 16:56

Jag gjorde så här:

lsb_release -a | sed -n '/Description/s/^.*:[\t ]*//p'

Marx 377
Postad: 27 nov 2021 18:53 Redigerad: 27 nov 2021 18:58
Laguna skrev:

Jag gjorde så här:

lsb_release -a | sed -n '/Description/s/^.*:[\t ]*//p'

Så här blir resultatet med din lösning:

Den första raden ska på något vis tas bort. Jag tror att det behövs att klämma in ett grepp-kommando mellan första och andra kommandon, som endast plockar raden innehållande "Description", eller fånga upp det första felmeddelandet genom att skriva lsb_release -a 2>/dev/null 

Laguna Online 30721
Postad: 27 nov 2021 19:09

Aha. Ja, felmeddelanden var jag inte beredd på, men det är inte säkert att man vill ignorera dem. Vad returnerar kommandot för statuskod i det fallet?

Marx 377
Postad: 28 nov 2021 13:27
Laguna skrev:

Aha. Ja, felmeddelanden var jag inte beredd på, men det är inte säkert att man vill ignorera dem. Vad returnerar kommandot för statuskod i det fallet?

När jag kör med echo $? för statuskoden så får jag 0 !!! Hur hänger det ihop med om det är ett felmeddelande med statuskoden 0 ?

Programmeraren 3390
Postad: 28 nov 2021 13:36 Redigerad: 28 nov 2021 13:36

Det är bara en information om att det inte finns något. Programmet ser inte det som ett error.

Om du kollar man-bladet, "man lsb_release", så ser du att du kan be om annan info mer specifikt med t ex
lsb_release -d

Laguna Online 30721
Postad: 28 nov 2021 13:44

Program kan skriva varningar på stderr och annat på stdout, men det skulle vara bra om det framgick att "No LSB modules available" var en varning.

Svara
Close