Kapitel 12. Programmering

# Kapitel 12. Programmering

Jag ger några tips för att människor ska lära sig programmering på Debian-systemet tillräckligt för att spåra den paketerade källkoden. Här är anmärkningsvärda paket och motsvarande dokumentationspaket för programmering.

Online-referenser finns tillgängliga genom att skriva "`man name`" efter installation av paketen `manpages` och `manpages-dev`. Online-referenser för GNU-verktygen finns tillgängliga genom att skriva "`info programnamn`" efter att du har installerat de relevanta dokumentationspaketen. Du kan behöva inkludera arkiven `contrib-` och `non-free` utöver `main` eftersom vissa GFDL-dokumentationer inte anses vara DFSG-kompatibla.

Tänk på att använda verktyg för versionskontrollsystem. Se Avsnitt 10.5, ”Git”.

| Varning
Använd inte "``test" som namn på en körbar testfil. "`test`" är en inbyggd funktion i skalet.

| Observera
Du bör installera program som är direkt kompilerade från källkod i "`/usr/local`" eller "`/opt`" för att undvika kollision med systemprogram.

| Tips
Kodexempel för att skapa "Song 99 Bottles of Beer" bör ge dig goda idéer om praktiskt taget alla programmeringsspråk.

## 12.1. Shell-skriptet

Shellskriptet är en textfil med exekveringsbiten aktiverad och innehåller kommandon i följande format.

    #!/bin/sh
     ... command lines

Den första raden anger vilken shell-tolk som ska läsa och exekvera filinnehållet.

Att läsa skalskript är det bästa sättet att förstå hur ett Unix-liknande system fungerar. Här ger jag några tips och påminnelser för programmering i skalet. Se "Shell Mistakes"(https://www.greenend.org.uk/rjk/2001/04/shell.html) för att lära dig av misstag.

Till skillnad från det interaktiva läget i shell (se Avsnitt 1.5, ”Det enkla shell-kommandot” och Avsnitt 1.6, ”Unix-liknande textbehandling”) används ofta parametrar, villkor och loopar i shell-skript.

### 12.1.1. POSIX shell-kompatibilitet

Många systemskript kan tolkas av något av POSIX-skalen (se Tabell 1.13, ”Lista över skalprogram”).

- Det icke-interaktiva POSIX-skalet "`/usr/bin/sh`" är en symbolisk länk som pekar på `/usr/bin/dash` och används av många systemprogram.

- Det interaktiva POSIX-shell som används som standard är `/usr/bin/bash`.

Undvik att skriva ett skalskript med bashisms eller zshisms för att göra det portabelt mellan alla POSIX-skal. Du kan kontrollera det med checkbashisms(1).

Tabell 12.1. Lista över typiska bashismer

Bra: POSIX | Undvik: bashism
--- | ---
`if [ "$foo" = "$bar" ] ; then …` | `if [ "$foo" == "$bar" ] ; then …`
`diff -u file.c.orig file.c` | `diff -u file.c{.orig,}`
`mkdir /foobar /foobaz` | `mkdir /foo{bar,baz}`
`funcname() { … }` | `function funcname() { … }`
oktalformat: "`\377`" | hexadecimalt format: "`\xff`"

Kommandot "`echo`" måste användas med försiktighet eftersom dess implementering skiljer sig mellan inbyggda och externa kommandon i skalet.

- Undvik att använda några kommandoval utom "`-n`".

- Undvik att använda escape-sekvenser i strängen eftersom hanteringen av dem varierar.

| Notera
Alternativet "`-n`" är inte riktigt POSIX-syntax, men det är allmänt accepterat.

| Tips
Använd kommandot "`printf`" i stället för kommandot "`echo`" om du behöver bädda in escape-sekvenser i utdatasträngen.

### 12.1.2. Parametrar för skal

Speciella shell-parametrar används ofta i shell-skriptet.

Tabell 12.2. Lista över skalparametrar

skalparameter | värde
--- | ---
`$0` | namnet på skalet eller skalskriptet
`$1` | första (1st) skalargumentet
`$9` | nionde (9:e) skalargumentet
`$#` | antal positionsparametrar
`"$*"` | `"$1 $2 $3 $4 … "`
`"$@"` | `"$1" "$2" "$3" "$4" …`
`$?` | utgångsstatus för det senaste kommandot
`$$` | PID för detta shell-skript
`$!` | PID för det senast startade bakgrundsjobbet

Grundläggande parameterutvidgningar att komma ihåg är följande.

Tabell 12.3. Lista över expansioner av skalparametrar

parameter uttryck form | värde om `var` är inställd | värde om `var` inte är inställd
--- | --- | ---
`${var:-string}` | "`$var`" | "`sträng`"
`${var:+string}` | "`sträng`" | "`null`"
`${var:=string}` | "`$var`" | "`string`" (och kör "`var=string`")
`${var:?string}` | "`$var`" | echo "`string`" till stderr (och avsluta med fel)

Här är kolon "`:`" i alla dessa operatorer faktiskt valfritt.

- med "`:`" = operatörstest för exist och inte null

- utan "`:`" = operatörstest för endast existera

Tabell 12.4. Lista över ersättningar för viktiga skalparametrar

formulär för parametersubstitution | resultat
--- | ---
`${var%suffix}` | ta bort minsta suffixmönster
`${var%%suffix}` | ta bort största suffixmönster
`${var#prefix}` | ta bort minsta prefixmönster
`${var##prefix}` | ta bort största prefixmönster

### 12.1.3. Villkor för skal

Varje kommando returnerar en utgångsstatus som kan användas för villkorliga uttryck.

- Framgång: 0 ("True")

- Fel: non 0 ("False")

| Notera
"0" i skalvillkorskontexten betyder "sant", medan "0" i C-villkorskontexten betyder "falskt".

| Notera
"`[`" är motsvarigheten till kommandot `test`, som utvärderar sina argument upp till "`]`" som ett villkorligt uttryck.

Grundläggande villkorliga idiom att komma ihåg är följande.

- "`kommando && if_success_run_this_command_too || true`"

- `"kommandot || if_not_success_run_this_command_too || true`"

- Ett skriptutdrag med flera rader enligt följande

    if [ conditional_expression ]; then
     if_success_run_this_command
    else
     if_not_success_run_this_command
    fi

Här behövdes det efterföljande "`|| true`" för att säkerställa att detta skalskript inte avslutas på denna rad av misstag när skalet anropas med flaggan "`-e`".

Tabell 12.5. Lista över operatorer för filjämförelse i det villkorliga uttrycket

ekvation | villkor som ska returnera logiskt sant
--- | ---
`-e file` | filen finns
`-d file` | filen finns och är en katalog
`-f fil` | filen finns och är en vanlig fil
`-w file` | filen finns och är skrivbar
`-x file` | filen finns och är körbar
`file1 -nt file2` | fil1 är nyare än fil2 (modifiering)
`file1 -ot file2` | fil1 är äldre än fil2 (modifiering)
`fil1 -ef fil2` | fil1 och fil2 finns på samma enhet och har samma inode-nummer

Tabell 12.6. Lista över operatorer för strängjämförelse i det villkorliga uttrycket

ekvation | villkor som ska returnera logiskt sant
--- | ---
`-z str` | längden på str är noll
`-n str` | längden på str är inte noll
`str1 = str2` | str1 och str2 är lika
`str1 != str2` | str1 och str2 är inte lika
`str1 < str2` | str1 sorteras före str2 (beroende på lokal)
`str1 > str2` | str1 sorteras efter str2 (lokalberoende)

Aritmetiska heltalsjämförelseoperatorer i det villkorliga uttrycket är "`-eq`", "`-ne`", "`-lt`", "`-le`", "`-gt`" och "`-ge`".

### 12.1.4. Öglor i skalet

Det finns flera loop-idiom som kan användas i POSIX-skal.

- "`for x in foo1 foo2 ... ; do command ; done`" loopar genom att tilldela objekt från listan "`foo1 foo2 ..."` till variabeln "`x`" och utföra "`command`".

- "`while condition ; do command ; done`" upprepar "`command`" medan "`condition`" är sant.

- "`until condition ; do command ; done`" upprepar "`command`" medan "`condition`" inte är sant.

- "`break`" gör det möjligt att lämna loopen.

- "`continue`" gör det möjligt att återuppta nästa iteration av loopen.

| Tips
Den numeriska iterationen som liknar C-språkets kan realiseras genom att använda seq(1) som generator för "`foo1 foo2 ...`".

| Tips
Se Avsnitt 9.4.9, ”Upprepa ett kommando loopa över filer”.

### 12.1.5. Shell-miljövariabler

Vissa populära miljövariabler för den normala kommandoprompten i shell kanske inte är tillgängliga i exekveringsmiljön för ditt skript.

- För "`$USER`", använd "`$(id -un)`"

- För "`$UID`", använd "`$(id -u)`"

- För "`$HOME`" använder du "`$(getent passwd "$(id -u)"|cut -d ":" -f 6)`" (detta fungerar även på Avsnitt 4.5.2, ”Den moderna centraliserade systemhanteringen”)

### 12.1.6. Bearbetningssekvensen för kommandoraden i Shell

Shell bearbetar ett skript ungefär enligt följande sekvens.

- Shell läser en rad.

- Skalet grupperar en del av raden som en token om den ligger inom "`..."` eller '... `'`.

- Shell delar upp andra delar av en rad i tokens på följande sätt.

  - Whitespaces: `mellanslag flik nytt streck`

  - Metatecken: `< > | ; & ( )`

- Skalet kontrollerar det reserverade ordet för varje token för att anpassa sitt beteende om det inte finns inom "`..."` eller '... `'`.

  - reserverat ord: `if then elif else fi for in while unless do done case esac`

- Skalet expanderar alias om det inte finns inom "`..."` eller `'`...'.

- Skalet expanderar tilde om det inte finns inom `"..."` eller '... '``.

  - "`~`" → den aktuella användarens hemkatalog

  - "`~användare`" → `användarens`användarens hemkatalog

- Skalet expanderar parametern till dess värde om den inte finns inom `'...'`.

  - parameter: "`$PARAMETER`" eller "`${PARAMETER}`"

- Skalet expanderar kommandosubstitutionen om den inte finns inom `'...'`.

  - "`$( kommando )`" → utdata från "`kommando`"

  - "``kommando ``" → utdata från "`kommando`"

- Skalet expanderar sökvägsnamnet glob till matchande filnamn om det inte finns inom `"..."` eller '...'``.

  - `*` → alla tecken

  - `?` → ett tecken

  - `[...]` → något av tecknen i "... "``

- Shell letar upp kommandot från följande och utför det.

  - definition av funktion

  - inbyggt kommando

  - körbar fil i "`$PATH`"

- Skalet går till nästa rad och upprepar denna process igen från början av denna sekvens.

Enkla citattecken inom dubbla citattecken har ingen effekt.

Om du kör "`set -x`" i skalet eller anropar skalet med alternativet "`-x`" skriver skalet ut alla kommandon som har körts. Detta är ganska praktiskt för felsökning.

### 12.1.7. Verktygsprogram för shell-skript

För att göra ditt skalprogram så portabelt som möjligt mellan olika Debian-system är det en god idé att begränsa hjälpprogrammen till sådana som tillhandahålls av viktiga paket.

- "`aptitude search ~E`" listar viktiga paket.

- "`dpkg -L paketnamn |grep '/man/man.*/'`" listar handböcker för kommandon som erbjuds av `paket_namn` paketet.

Tabell 12.7. Lista över paket som innehåller små verktygsprogram för skalskript

paket | popcon | storlek | beskrivning
--- | --- | --- | ---
`dash` | V:928, I:998 | 207 | litet och snabbt POSIX-kompatibelt skal för `sh`
`coreutils` | V:910, I:1000 | 17994 | GNU:s centrala verktyg
`grep` | V:779, I:1000 | 1297 | GNU `grep`, `egrep` och `fgrep`
`sed` | V:762, I:1000 | 987 | GNU `sed`
`mawk` | V:485, I:998 | 295 | liten och snabb `awk`
`debianutils` | V:936, I:997 | 225 | diverse verktyg som är specifika för Debian
`bsdutils` | V:445, I:1000 | 338 | grundläggande verktyg från 4.4BSD-Lite
`bsdextrautils` | V:754, I:863 | 382 | extra verktyg från 4.4BSD-Lite
`moreutils` | V:18, I:39 | 232 | ytterligare Unix-verktyg

| Tips
Även om `moreutils` kanske inte existerar utanför Debian, erbjuder det intressanta små program. Det mest anmärkningsvärda är sponge(8) som är ganska användbart när du vill skriva över originalfilen.

Se Avsnitt 1.6, ”Unix-liknande textbehandling” för exempel.

## 12.2. Skriptning i tolkade språk

Tabell 12.8. Lista över tolkrelaterade paket

paket | popcon | storlek | dokumentation
--- | --- | --- | ---
`dash` | V:928, I:998 | 207 | sh: litet och snabbt POSIX-kompatibelt skal för `sh`
`bash` | V:893, I:1000 | 7309 | sh: "`info bash`" tillhandahålls av `bash-doc`
`mawk` | V:485, I:998 | 295 | AWK: liten och snabb `awk`
`gawk` | V:250, I:301 | 3289 | AWK: "`info gawk`" tillhandahålls av `gawk-doc`
`perl` | V:673, I:992 | 836 | Perl: perl(1) och html-sidor tillhandahålls av `perl-doc` och `perl-doc-html`
`libterm-readline-gnu-perl` | V:2, I:27 | 439 | Perl-tillägg för GNU ReadLine/History Library: perlsh(1)
`libreply-perl` | V:0.01, I:0.10 | 171 | REPL för Perl: svar(1)
`libdevel-repl-perl` | V:0.03, I:0.57 | 237 | REPL för Perl: re.pl(1)
`python3` | V:717, I:974 | 80 | Python: python3(1) och html-sidor tillhandahålls av `python3-doc`
`tcl` | V:23, I:176 | 20 | Tcl: tcl(3) och detaljerade manualsidor som tillhandahålls av `tcl-doc`
`tk` | V:17, I:169 | 20 | Tk: tk(3) och detaljerade manualsidor som tillhandahålls av `tk-doc`
`ruby` | V:71, I:157 | 32 | Ruby: ruby(1), erb(1), irb(1), rdoc(1), ri(1)

När du vill automatisera en uppgift på Debian bör du först skripta den med ett tolkat språk. Riktlinjerna för valet av tolkat språk är:

- Använd `dash` om det handlar om en enkel uppgift som kombinerar CLI-program med ett skalprogram.

- Använd `python3`, om uppgiften inte är enkel och du skriver den från grunden.

- Använd `perl`, `tcl`, `ruby`, ... om det finns en befintlig kod som använder något av dessa språk på Debian som behöver förbättras för att utföra uppgiften.

Om den resulterande koden är för långsam kan du skriva om endast den del som är kritisk för exekveringshastigheten i ett kompilerat språk och anropa den från det tolkade språket.

### 12.2.1. Felsökning av tolkade språkkoder

De flesta tolkar erbjuder grundläggande funktioner för syntaxkontroll och kodspårning.

- "dash -n script.sh" - Syntaxkontroll av ett Shell-skript

- "dash -x script.sh" - Spåra ett Shell-skript

- "python-m py_compile script .py" - Syntaxkontroll av ett Python-skript

- "python -mtrace --trace script .py" - Spåra ett Python-skript

- "perl -I ../libpath -c script.pl" - Syntaxkontroll av ett Perl-skript

- "perl -d: Trace script.pl" - Spåra ett Perl-skript

För att testa kod för `dash`, prova Avsnitt 9.1.4, ”Omslag för läslinje” som rymmer `bash-liknande` interaktiv miljö.

För att testa kod för `Perl`, prova REPL-miljö för Perl som rymmer Python-liknande REPL (=READ + EVAL + PRINT + LOOP) -miljö för Perl.

### 12.2.2. GUI-program med shell-skript

Shell-skriptet kan förbättras för att skapa ett attraktivt GUI-program. Tricket är att använda något av de s.k. dialogprogrammen istället för tråkig interaktion `med echo` och `read-kommandon`.

Tabell 12.9. Lista över dialogprogram

paket | popcon | storlek | beskrivning
--- | --- | --- | ---
`x11-utils` | V:222, I:551 | 651 | xmessage(1): visa ett meddelande eller en fråga i ett fönster (X)
`whiptail` | V:303, I:997 | 61 | visar användarvänliga dialogrutor från shell-skript (newt)
`dialog` | V:8, I:77 | 520 | visar användarvänliga dialogrutor från shell-skript (ncurses)
`zenity` | V:74, I:338 | 193 | visa grafiska dialogrutor från skalskript (GTK)
`ssft` | V:0.01, I:0.16 | 80 | Shell Scripts Frontend Tool (wrapper för zenity, kdialog och dialog med gettext)
`gettext` | V:51, I:216 | 20468 | "`/usr/bin/gettext.sh`": översätt meddelande

Här är ett exempel på ett GUI-program som visar hur enkelt det är att bara använda ett skalskript.

Detta skript använder `zenity` för att välja en fil (standard `/etc/motd`) och visa den.

GUI-startprogrammet för detta skript kan skapas enligt Avsnitt 9.4.10, ”Starta ett program från GUI”.

    #!/bin/sh -e
    # Copyright (C) 2021 Osamu Aoki <osamu@debian.org>, Public Domain
    # vim:set sw=2 sts=2 et:
    DATA_FILE=$(zenity --file-selection --filename="/etc/motd" --title="Select a file to check") || \
      ( echo "E: File selection error" >&2 ; exit 1 )
    # Check size of archive
    if ( file -ib "$DATA_FILE" | grep -qe '^text/' ) ; then
      zenity --info --title="Check file: $DATA_FILE" --width 640  --height 400 \
        --text="$(head -n 20 "$DATA_FILE")"
    else
      zenity --info --title="Check file: $DATA_FILE" --width 640  --height 400 \
        --text="The data is MIME=$(file -ib "$DATA_FILE")"
    fi

Den här typen av tillvägagångssätt för GUI-program med shell-skript är endast användbart för enkla val. Om du ska skriva något program med komplexitet bör du överväga att skriva det på en mer kapabel plattform.

### 12.2.3. Anpassade åtgärder för GUI-fil

GUI-filprogram kan utökas för att utföra vissa populära åtgärder på utvalda filer med hjälp av ytterligare tilläggspaket. De kan också göras för att utföra mycket specifika anpassade åtgärder genom att lägga till dina specifika skript.

- För GNOME, se NautilusScriptsHowto.

- För KDE, se Skapa Dolphins servicemenyer.

- För Xfce, se Thunar - Anpassade åtgärder och https://help.ubuntu.com/community/ThunarCustomActions.

- För LXDE, se Anpassade åtgärder.

### 12.2.4. Perl kortskript galenskap

För att bearbeta data måste `sh` skapa underprocesser som kör `cut`, `grep`, `sed`, etc. och är långsamma. Å andra sidan har `perl` interna funktioner för att bearbeta data och är snabb. Så många systemunderhållsskript på Debian använder `perl`.

Låt oss tänka på följande one-liner AWK-skriptutdrag och dess motsvarigheter i Perl.

    awk '($2=="1957") { print $3 }' |

Detta är likvärdigt med någon av följande rader.

    perl -ne '@f=split; if ($f[1] eq "1957") { print "$f[2]\n"}' |

    perl -ne 'if ((@f=split)[1] eq "1957") { print "$f[2]\n"}' |

    perl -ne '@f=split; print $f[2] if ( $f[1]==1957 )' |

    perl -lane 'print $F[2] if $F[1] eq "1957"' |

    perl -lane 'print$F[2]if$F[1]eq+1957' |

Den sista är en gåta. Den utnyttjade följande Perl-funktioner.

- Det vita tecknet är valfritt.

- Den automatiska konverteringen sker från tal till sträng.

- Tricks för Perl-körning via kommandoradsalternativ: perlrun(1)

- Specialvariabler för Perl: perlvar(1)

Denna flexibilitet är styrkan i Perl. Samtidigt gör det att vi kan skapa kryptiska och trassliga koder. Så var försiktig.

## 12.3. Kodning i kompilerade språk

Tabell 12.10. Lista över kompilatorrelaterade paket

paket | popcon | storlek | beskrivning
--- | --- | --- | ---
`gcc` | V:155, I:564 | 36 | GNU C-kompilator
`libc6-dev` | V:269, I:584 | 12861 | GNU C-biblioteket: Utvecklingsbibliotek och huvudfiler
`g++` | V:57, I:531 | 13 | GNU C++-kompilator
`libstdc++-16-dev` | V:0.7, I:4.3 | 24382 | GNU Standard C++ Library v3 (utvecklingsfiler)
`cpp` | V:332, I:719 | 18 | GNU C preprocessor
`gettext` | V:51, I:216 | 20468 | GNU:s internationaliseringsverktyg
`glade` | V:0.7, I:2.7 | 1613 | GTK-byggare för användargränssnitt
`valac` | V:0.2, I:3.2 | 533 | C#-liknande språk för GObject-systemet
`flex` | V:7, I:68 | 1247 | LEX-kompatibel snabb generator för lexikal analys
`bison` | V:7, I:73 | 3122 | YACC-kompatibel parser-generator
`susv2` | I:0.03 | 16 | hämta"The Single UNIX Specifications v2"
`susv3` | I:0.06 | 16 | hämta"The Single UNIX Specifications v3"
`susv4` | I:0.04 | 16 | hämta"The Single UNIX Specifications v4"
`golang` | I:22 | 12 | Go programmeringsspråk kompilator
`rustc` | V:5, I:20 | 13061 | Rust system programmeringsspråk
`gfortran` | V:4, I:50 | 15 | GNU Fortran 95-kompilator
`fpc` | I:2.3 | 101 | Fri Pascal

Här ingår Avsnitt 12.3.3, ”Flex - en bättre Lex” och Avsnitt 12.3.4, ”Bison - en bättre Yacc” för att visa hur ett kompilatorliknande program kan skrivas i C-språk genom att kompilera en beskrivning på högre nivå till C-språk.

### 12.3.1. C

Du kan skapa en lämplig miljö för att kompilera program som är skrivna i programmeringsspråket C genom att göra följande.

    # apt-get install glibc-doc manpages-dev libc6-dev gcc build-essential

Paketet `libc6-dev`, dvs GNU C Library, tillhandahåller C-standardbiblioteket som är en samling av rubrikfiler och biblioteksrutiner som används av programmeringsspråket C.

Se referenser för C som följande.

- "`info libc`" (referens till C-bibliotekets funktioner)

- gcc(1) och "`info gcc`"

- varje_C_biblioteks_funktionsnamn(3)

- Kernighan & Ritchie, "The C Programming Language", 2:a upplagan (Prentice Hall)

### 12.3.2. Enkelt C-program (gcc)

Ett enkelt exempel "`.c`" kan kompileras med ett bibliotek "`libm`" till en körbar fil "`run_example`" på följande sätt.

    $ cat > example.c << EOF
    #include <stdio.h>
    #include <math.h>
    #include <string.h>

    int main(int argc, char **argv, char **envp){
            double x;
            char y[11];
            x=sqrt(argc+7.5);
            strncpy(y, argv[0], 10); /* prevent buffer overflow */
            y[10] = '\0'; /* fill to make sure string ends with '\0' */
            printf("%5i, %5.3f, %10s, %10s\n", argc, x, y, argv[1]);
            return 0;
    }
    EOF
    $ gcc -Wall -g -o run_example example.c -lm
    $ ./run_example
            1, 2.915, ./run_exam,     (null)
    $ ./run_example 1234567890qwerty
            2, 3.082, ./run_exam, 1234567890qwerty

Här behövs "`-lm`" för att länka biblioteket "`/usr/lib/libm.so"` från `libc6-paketet` för sqrt(3). Det faktiska biblioteket finns i "`/lib/`" med filnamnet "libm.`so.6`", som är en symlänk till "`libm-2.7.so"`.

Titta på den sista parametern i utdatatexten. Det finns mer än 10 tecken trots att "`%10s`" har angetts.

Användningen av funktioner för pekarminnesoperationer utan gränskontroller, t.ex. sprintf(3) och strcpy(3), avråds för att förhindra buffer overflow-exploateringar som utnyttjar ovanstående överskridningseffekter. Använd istället snprintf(3) och strncpy(3).

### 12.3.3. Flex - en bättre Lex

Flex är en Lex-kompatibel snabb generator för lexikal analys.

Handledning för flex(1) kan hittas i "`info flex`".

Många enkla exempel finns under "`/usr/share/doc/flex/examples/`". [7]

### 12.3.4. Bison - en bättre Yacc

Flera paket tillhandahåller en Yacc-kompatibel lookahead LR-parser eller LALR-parsergenerator i Debian.

Tabell 12.11. Lista över Yacc-kompatibla LALR-parser-generatorer

paket | popcon | storlek | beskrivning
--- | --- | --- | ---
`bison` | V:7, I:73 | 3122 | Generator för GNU LALR-parser
`byacc` | V:0.1, I:3.0 | 263 | Generator för Berkeley LALR-parser
`btyacc` | V:0.01, I:0.06 | 247 | parsergenerator för backtracking baserad på `byacc`

Handledning för bison(1) finns i "`info bison`".

Du måste tillhandahålla dina egna "`main()`" och "`yyerror(`)". "`main()`"`anropar "yyparse()" som anropar` "`yylex(`)", vanligtvis skapat med Flex.

Här följer ett exempel på hur du skapar ett enkelt kalkylatorprogram för terminalen.

Låt oss skapa `exempel.y`:

    /* calculator source for bison */
    %{
    #include <stdio.h>
    extern int yylex(void);
    extern int yyerror(char *);
    %}

    /* declare tokens */
    %token NUMBER
    %token OP_ADD OP_SUB OP_MUL OP_RGT OP_LFT OP_EQU

    %%
    calc:
     | calc exp OP_EQU    { printf("Y: RESULT = %d\n", $2); }
     ;

    exp: factor
     | exp OP_ADD factor  { $$ = $1 + $3; }
     | exp OP_SUB factor  { $$ = $1 - $3; }
     ;

    factor: term
     | factor OP_MUL term { $$ = $1 * $3; }
     ;

    term: NUMBER
     | OP_LFT exp OP_RGT  { $$ = $2; }
      ;
    %%

    int main(int argc, char **argv)
    {
      yyparse();
    }

    int yyerror(char *s)
    {
      fprintf(stderr, "error: '%s'\n", s);
    }

Låt oss skapa, `exempel.l`:

    /* calculator source for flex */
    %{
    #include "example.tab.h"
    %}

    %%
    [0-9]+ { printf("L: NUMBER = %s\n", yytext); yylval = atoi(yytext); return NUMBER; }
    "+"    { printf("L: OP_ADD\n"); return OP_ADD; }
    "-"    { printf("L: OP_SUB\n"); return OP_SUB; }
    "*"    { printf("L: OP_MUL\n"); return OP_MUL; }
    "("    { printf("L: OP_LFT\n"); return OP_LFT; }
    ")"    { printf("L: OP_RGT\n"); return OP_RGT; }
    "="    { printf("L: OP_EQU\n"); return OP_EQU; }
    "exit" { printf("L: exit\n");   return YYEOF; } /* YYEOF = 0 */
    .      { /* ignore all other */ }
    %%

Kör sedan följande från shellprompten för att prova detta:

    $ bison -d example.y
    $ flex example.l
    $ gcc -lfl example.tab.c lex.yy.c -o example
    $ ./example
    1 + 2 * ( 3 + 1 ) =
    L: NUMBER = 1
    L: OP_ADD
    L: NUMBER = 2
    L: OP_MUL
    L: OP_LFT
    L: NUMBER = 3
    L: OP_ADD
    L: NUMBER = 1
    L: OP_RGT
    L: OP_EQU
    Y: RESULT = 9

    exit
    L: exit

## 12.4. Verktyg för statisk kodanalys

Lint-liknande verktyg kan hjälpa till med automatisk statisk kodanalys.

Indragningsliknande verktyg kan underlätta mänskliga kodgranskningar genom att omformatera källkoder på ett konsekvent sätt.

Taggar som verktyg kan hjälpa mänskliga kodgranskare genom att generera en indexfil (eller taggfil) med namn som finns i källkoder.

| Tips
Om du konfigurerar din favoritredigerare (`emacs` eller `vim`) så att den använder asynkrona insticksmoduler för lint-motorer blir det lättare att skriva kod. Dessa insticksmoduler blir mycket kraftfulla genom att dra nytta av Language Server Protocol. Eftersom de utvecklas snabbt kan det vara ett bra alternativ att använda deras uppströmskod istället för Debian-paketet.

Tabell 12.12. Lista över verktyg för statisk kodanalys

paket | popcon | storlek | beskrivning
--- | --- | --- | ---
`vim-ale` | I:0.80 | 2833 | Asynkron Lint-motor för Vim 8 och NeoVim
`vim-syntastic` | I:2.0 | 1379 | Syntaxkontroll-hacks för vim
`elpa-flycheck` | V:0.1, I:1.7 | 1130 | modern on-the-fly syntaxkontroll för Emacs
`elpa-relint` | I:0.06 | 150 | Emacs Lisp regexp misstagssökare
`cppcheck-gui` | V:0.1, I:1.0 | 7697 | verktyg för statisk analys av C/C++-kod (GUI)
`shellcheck` | V:3, I:16 | 22860 | lint-verktyg för shell-skript
`pyflakes3` | V:1, I:12 | 20 | passiv kontroll av Python 3-program
`pylint` | V:3, I:17 | 2093 | Statisk kontroll av Python-kod
`perl` | V:673, I:992 | 836 | tolk med intern statisk kodkontroll: `B::Lint`(3perl)
`rubocop` | V:0.1, I:1.1 | 4192 | Analysator för statisk kod i Ruby
`clang-tidy` | V:2, I:10 | 21 | clang-baserat C++ linter-verktyg
`splint` | V:0.06, I:0.92 | 2325 | verktyg för att statiskt kontrollera C-program för buggar
`flawfinder` | V:0.07, I:0.49 | 187 | verktyg för att undersöka C/C++-källkod och leta efter säkerhetsbrister
`black` | V:2, I:13 | 10057 | kompromisslös Python-kodformaterare
`perltidy` | V:0.4, I:3.1 | 3086 | Indenterare och omformaterare av Perl-skript
`indent` | V:0.8, I:5.1 | 438 | C-språk källkod formateringsprogram
`astyle` | V:0.2, I:2.7 | 770 | Källkodsindenter för C, C++, Objective-C, C# och Java
`bcpp` | V:0.02, I:0.26 | 114 | C(++) förskönare
`xmlindent` | V:0.05, I:0.79 | 52 | Omformatering av XML-ström
`global` | V:0.2, I:1.6 | 1923 | Verktyg för att söka och bläddra i källkod
`exuberant-ctags` | V:2, I:13 | 341 | skapa taggfilsindex för källkodsdefinitioner
`universal-ctags` | V:2, I:10 | 4238 | skapa taggfilsindex för källkodsdefinitioner

## 12.5. Debugg

Felsökning är en viktig del av programmeringsaktiviteter. Att veta hur man felsöker program gör dig till en bra Debian-användare som kan producera meningsfulla felrapporter.

Tabell 12.13. Lista över felsökningspaket

paket | popcon | storlek | dokumentation
--- | --- | --- | ---
`gdb` | V:88, I:161 | 12453 | "`info gdb`" tillhandahålls av `gdb-doc`
`ddd` | V:0.7, I:5.2 | 4210 | "`info ddd`" tillhandahålls av `ddd-doc`

### 12.5.1. Grundläggande gdb-körning

Den primära felsökaren på Debian är gdb(1) som gör att du kan inspektera ett program medan det körs.

Låt oss installera `gdb` och relaterade program enligt följande.

    # apt-get install gdb gdb-doc build-essential devscripts

Bra handledning av `gdb` kan hittas:

- "`info gdb`"

- "Felsökning med GDB" i `/usr/share/doc/gdb-doc/html/gdb/index.html`

- "handledning på webben"

Här följer ett enkelt exempel på hur du använder gdb(1) på ett "`program`" som kompilerats med alternativet "`-g`" för att ta fram felsökningsinformation.

    $ gdb program
    (gdb) b 1                # set break point at line 1
    (gdb) run args           # run program with args
    (gdb) next               # next line
    ...
    (gdb) step               # step forward
    ...
    (gdb) p parm             # print parm
    ...
    (gdb) p parm=12          # set value to 12
    ...
    (gdb) quit

| Tips
Många gdb(1)-kommandon kan förkortas. Tabbexpansion fungerar som i skalet.

### 12.5.2. Felsökning av Debian-paketet

Eftersom alla installerade binärfiler som standard bör vara strippade på Debian-systemet, tas de flesta felsökningssymbolerna bort i det normala paketet. För att kunna felsöka Debian-paket med gdb(1) måste `*-dbgsym-paket` installeras (t.ex. `coreutils-dbgsym` när det gäller `coreutils`). Källpaketen genererar `*-dbgsym-paket` automatiskt tillsammans med normala binära paket och dessa felsökningspaket placeras separat i debian-debug-arkivet. Se artiklar på Debian Wiki för mer information.

Om ett paket som ska felsökas inte tillhandahåller sitt `*-dbgsym-paket` måste du installera det efter att ha byggt upp det på följande sätt.

    $ mkdir /path/new ; cd /path/new
    $ sudo apt-get update
    $ sudo apt-get dist-upgrade
    $ sudo apt-get install fakeroot devscripts build-essential
    $ apt-get source package_name
    $ cd package_name*
    $ sudo apt-get build-dep ./

Åtgärda buggar om det behövs.

Förbättra paketversionen till en som inte kolliderar med officiella Debian-versioner, t.ex. en som har tillägget "`+debug1`" vid omkompilering av befintlig paketversion, eller en som har tillägget "`~pre1`" vid kompilering av outgiven paketversion genom följande.

    $ dch -i

Kompilera och installera paket med debug-symboler med följande.

    $ export DEB_BUILD_OPTIONS="nostrip noopt"
    $ debuild
    $ cd ..
    $ sudo debi package_name*.changes

Du måste kontrollera paketets byggskript och se till att du använder "`CFLAGS=-g -Wall`" för att kompilera binärfiler.

### 12.5.3. Hämta bakspårning

När du stöter på programkrasch är det en bra idé att rapportera felrapport med klippt och klistrat backtrace-information.

Bakspårningen kan hämtas av gdb(1) med hjälp av något av följande tillvägagångssätt:

- Crash-in-GDB-metoden:

  - Kör programmet från GDB.

  - Krascha programmet.

  - Skriv "`bt`" i GDB-prompten.

- Först till kvarn när olyckan är framme:

  - Uppdatera filen "/etc/security/limits.conf" så att den innehåller följande:

        * soft core unlimited

  - Skriv "`ulimit -c unlimited`" i shellprompten.

  - Kör programmet från denna shell-prompt.

  - Krascha programmet för att producera en kärndumpfil.

  - Läs in minnesdumpfilen till GDB som "`gdb gdb ./program_binary core`" .

  - Skriv "`bt`" i GDB-prompten.

Vid oändlig loop eller fruset tangentbord kan du tvinga programmet att krascha genom att trycka på `Ctrl\` eller `Ctrl-C` eller köra "`kill -ABRT PID`". (Se Avsnitt 9.4.12, ”Döda en process”)

| Tips

Ofta ser man en backtrace där en eller flera av de översta raderna är i "`malloc()`" eller "`g_malloc(`)". När detta händer är chansen stor att din backtrace inte är särskilt användbar. Det enklaste sättet att hitta användbar information är att ställa in miljövariabeln "`$MALLOC_CHECK_`" till ett värde av 2 (malloc(3)). Du kan göra detta medan du kör `gdb` genom att göra följande.

     $ MALLOC_CHECK_=2 gdb hello

### 12.5.4. Avancerade gdb-kommandon

Tabell 12.14. Lista över avancerade gdb-kommandon

kommando | beskrivning för ledningsmål
--- | ---
`(gdb) thread apply all bt` | få en backtrace för alla trådar för flertrådade program
`(gdb) bt full` | hämta parametrar som kom på stacken i funktionsanrop
`(gdb) thread apply all bt full` | få en backtrace och parametrar som en kombination av de föregående alternativen
`(gdb) thread apply all bt full 10` | få en backtrace och parametrar för topp 10-anrop för att skära bort irrelevanta utdata
`(gdb) set logging on` | skriva logg över `gdb-utdata` till en fil (standard är "`gdb.txt`")

### 12.5.5. Kontrollera beroendet av bibliotek

Använd ldd(1) för att ta reda på hur beroende ett program är av bibliotek enligt följande.

    $ ldd /usr/bin/ls
            librt.so.1 => /lib/librt.so.1 (0x4001e000)
            libc.so.6 => /lib/libc.so.6 (0x40030000)
            libpthread.so.0 => /lib/libpthread.so.0 (0x40153000)
            /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

För att ls(1) ska fungera i en `chroot`-miljö måste ovanstående bibliotek finnas tillgängliga i din `chroot`-miljö.

Se Avsnitt 9.4.6, ”Spårning av programaktiviteter”.

### 12.5.6. Dynamiska verktyg för samtalsspårning

Det finns flera verktyg för dynamisk anropsspårning tillgängliga i Debian. Se Avsnitt 9.4, ”Övervakning, kontroll och start av programaktiviteter”.

### 12.5.7. Felsökning av X-fel

Om ett GNOME-program `preview1` har fått ett X-fel, bör du se ett meddelande enligt följande.

    The program 'preview1' received an X Window System error.

Om så är fallet kan du prova att köra programmet med "`--sync`" och bryta på funktionen "`gdk_x_error`" för att få en backtrace.

### 12.5.8. Verktyg för detektering av minnesläckor

Det finns flera verktyg för att upptäcka minnesläckor i Debian.

Tabell 12.15. Lista över verktyg för detektering av minnesläckage

paket | popcon | storlek | beskrivning
--- | --- | --- | ---
`libc6-dev` | V:269, I:584 | 12861 | mtrace(1): malloc-felsökningsfunktionalitet i glibc
`valgrind` | V:4, I:31 | 89318 | minnesfelsökare och profilerare
`electric-fence` | V:0.2, I:2.3 | 69 | malloc(3) felsökare
`libdmalloc5` | V:0.01, I:0.61 | 373 | bibliotek för minnesallokering för felsökning
`duma` | V:0.00, I:0.06 | 297 | bibliotek för att upptäcka buffertöverskridanden och -underskridanden i C- och C++-program
`leaktracer` | V:0.01, I:0.33 | 56 | minnesläcksökare för C++-program

### 12.5.9. Demontera binär

Du kan demontera binär kod med objdump(1) på följande sätt.

    $  objdump -m i386 -b binary -D /usr/lib/grub/x86_64-pc/stage1

| Notera
gdb(1) kan användas för att plocka isär kod interaktivt.

## 12.6. Bygg verktyg

Tabell 12.16. Lista över byggverktygspaket

paket | popcon | storlek | dokumentation
--- | --- | --- | ---
`make` | V:150, I:566 | 1762 | "`info make`" tillhandahålls av `make-doc`
`autoconf` | V:29, I:200 | 2244 | "`info autoconf`" tillhandahålls av `autoconf-doc`
`automake` | V:28, I:199 | 1932 | "`info automake`" tillhandahålls av `automake1.10-doc`
`libtool` | V:24, I:183 | 1245 | "`info libtool`" tillhandahålls av `libtool-doc`
`cmake` | V:21, I:123 | 59735 | cmake(1) make-system med öppen källkod och plattformsoberoende
`ninja-build` | V:9, I:55 | 456 | ninja(1) litet byggsystem närmast i anda till Make
`meson` | V:6, I:29 | 4278 | meson(1) högproduktivt byggsystem på toppen av `ninja`
`xutils-dev` | V:0.9, I:7.0 | 1495 | imake(1), xmkmf(1), etc.

### 12.6.1. Märke

Make är ett verktyg för att underhålla grupper av program. Vid exekvering av make(1) läser `make` regelfilen "`Makefile`" och uppdaterar ett mål om det är beroende av förutsättningsfiler som har ändrats sedan målet senast ändrades, eller om målet inte existerar. Exekveringen av dessa uppdateringar kan ske samtidigt.

Syntaxen för regelfilen är följande.

    target: [ prerequisites ... ]
     [TAB]  command1
     [TAB]  -command2 # ignore errors
     [TAB]  @command3 # suppress echoing

Här är "`[TAB]`" en TAB-kod. Varje rad tolkas av skalet efter att variabeln har bytts ut. Använd "`\`" i slutet av en rad för att fortsätta skriptet. Använd "`$$`" för att ange "`$`" för miljövärden i ett skalskript.

Implicita regler för mål och förutsättningar kan skrivas till exempel enligt följande.

    %.o: %.c header.h

Här innehåller målet tecknet "`%`" (exakt ett av dem). "`%`" kan matcha alla icke-tomma delsträngar i de faktiska målfilnamnen. Förutsättningarna använder också "`%`" för att visa hur deras namn förhåller sig till det faktiska målnamnet.

Tabell 12.17. Lista över make automatic-variabler

automatisk variabel | värde
--- | ---
`$@` | lokation
`$<` | första förutsättningen
`$?` | alla nyare förutsättningar
`$^` | alla förkunskapskrav
`$*` | "`%`" matchad stam i målmönstret

Tabell 12.18. Lista över utvidgningar av märkesvariabler

variabel expansion | beskrivning
--- | ---
`foo1 := bar` | engångsexpansion
`foo2 = bar` | rekursiv expansion
`foo3 += bar` | bifoga

Kör "`make -p -f/dev/null`" för att se automatiska interna regler.

### 12.6.2. Autotools

Autotools är en uppsättning programmeringsverktyg som är utformade för att hjälpa till att göra källkodspaket portabla till många Unix-liknande system.

- Autoconf är ett verktyg för att producera ett skalskript "`configure`" från "`configure.ac`".

  - "`configure`" används senare för att producera "`Makefile`" från "`Makefile.in`"-mallen.

- Automake är ett verktyg för att producera "`Makefile.in`" från "`Makefile.am`".

- Libtool är ett skalskript för att lösa problemet med programvaruportabilitet när delade bibliotek kompileras från källkod.

#### 12.6.2.1. Kompilera och installera ett program

| Varning
Skriv inte över systemfiler med dina kompilerade program när du installerar dem.

Debian rör inte filer i "`/usr/local/`" eller "`/opt`". Så om du kompilerar ett program från källkod, installera det i "`/usr/local/`" så att det inte stör Debian.

    $ cd src
    $ ./configure --prefix=/usr/local
    $ make # this compiles program
    $ sudo make install # this installs the files in the system

#### 12.6.2.2. Avinstallera program

Om du har originalkällan och om den använder autoconf(1)`/automake`(1) och om du kan komma ihåg hur du konfigurerade den, gör du så här för att avinstallera programmet.

    $ ./configure all-of-the-options-you-gave-it
    $ sudo make uninstall

Alternativt, om du är helt säker på att installationsprocessen bara lägger filer under "`/usr/local/`" och att det inte finns något viktigt där, kan du radera allt innehåll på följande sätt.

    # find /usr/local -type f -print0 | xargs -0 rm -f

Om du inte är säker på var filer är installerade bör du överväga att använda checkinstall(8) från `checkinstall-paketet`, vilket ger en ren sökväg för avinstallationen. Det finns nu stöd för att skapa ett Debian-paket med alternativet "`-D`".

### 12.6.3. Meson

Systemet för programvaruutveckling har utvecklats:

- Autotools på toppen av Make har varit de facto-standarden för den portabla bygginfrastrukturen sedan 1990-talet. Detta är extremt långsamt.

- CMake, som ursprungligen släpptes 2000, förbättrade hastigheten avsevärt men byggdes ursprungligen på toppen av den i sig långsamma Make. (Nu kan Ninja vara dess backend.)

- Ninja, som ursprungligen släpptes 2012, är tänkt att ersätta Make för den ytterligare förbättrade bygghastigheten och är utformad för att få sina indatafiler genererade av ett byggsystem på högre nivå.

- Meson, som ursprungligen släpptes 2013, är det nya populära och snabba byggsystemet på högre nivå som använder Ninja som backend.

Se dokument som finns på"The Meson Build system" och "The Ninja build system".

## 12.7. Webb

Enkla interaktiva dynamiska webbsidor kan skapas på följande sätt.

- Frågorna presenteras för webbläsaren med hjälp av HTML-formulär.

- Genom att fylla i och klicka på formulärposterna skickas en av följande URL-strängar med kodade parametrar från webbläsaren till webbservern.

  - "`https://www.foo.dom/cgi-bin/program.pl?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3`"

  - "`https://www.foo.dom/cgi-bin/program.py?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3`"

  - "`https://www.foo.dom/program.php?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3`"

- "`%nn" i URL ersätts med ett tecken med hexadecimalt` `nn-värde`.

- Miljövariabeln är inställd som: "`QUERY_STRING="VAR1=VAL1 VAR2=VAL2 VAR3=VAL3"`".

- CGI-program (vilket som helst av "`program.*`") på webbservern kör sig själv med miljövariabeln "`$QUERY_STRING`".

- `stdout` från CGI-programmet skickas till webbläsaren och presenteras som en interaktiv dynamisk webbsida.

Av säkerhetsskäl är det bättre att inte själv skapa nya hack för att tolka CGI-parametrar. Det finns etablerade moduler för dem i Perl och Python. PHP kommer med dessa funktioner. När lagring av klientdata behövs används HTTP-cookies. När databehandling på klientsidan behövs används ofta Javascript.

För mer information, se Common Gateway Interface, Apache Software Foundation och JavaScript.

Att söka på "CGI tutorial" på Google genom att skriva in den kodade URL:en https://www.google.com/search?hl=en&ie=UTF-8&q=CGI+tutorial direkt i webbläsarens adress är ett bra sätt att se CGI-skriptet i aktion på Googles server.

## 12.8. Översättning av källkoden

Det finns program för att konvertera källkoder.

Tabell 12.19. Lista över verktyg för översättning av källkod

paket | popcon | storlek | sökord | beskrivning
--- | --- | --- | --- | ---
`perl` | V:673, I:992 | 836 | AWK→PERL | konvertera källkoder från AWK till PERL: a2p(1)
`f2c` | V:0.1, I:2.0 | 443 | FORTRAN→C | konvertera källkoder från FORTRAN 77 till C/C++: f2c(1)
`intel2gas` | V:0.02, I:0.19 | 178 | intel→gas | konverterare från NASM (Intel-format) till GNU Assembler (GAS)

## 12.9. Skapa Debian-paket

Om du vill skapa ett Debian-paket ska du läsa följande.

- Kapitel 2, Debians pakethantering för att förstå det grundläggande paketsystemet

- Avsnitt 2.7.13, ”Portering av ett paket till det stabila systemet” att förstå den grundläggande portningsprocessen

- Avsnitt 9.11.4, ”Chroot-system” för att förstå grundläggande chroot-tekniker

- debuild(1) och sbuild(1)

- Avsnitt 12.5.2, ”Felsökning av Debian-paketet” för omkompilering för felsökning

- Guide för Debians underhållsansvariga (paketet `debmake-doc` )

- Debian Developer's Reference (paketet med `referenser för utvecklare` )

- Debians policyhandbok (paketet `debian-policy` )

Det finns paket som `debmake`, `dh-make`, `dh-make-perl` etc. som hjälper till med paketering.

[7] Vissa justeringar kan krävas för att få dem att fungera under det nuvarande systemet.

Kapitel 11. Konvertering av data |  | Appendix A. Appendix