Prof. Dr.-Ing. Oliver Radfelder
Informatik / Wirtschaftsinformatik
Hochschule Bremerhaven
Snippets
Hier sammle ich kleine Schnipsel von Programmcode oder Konfigurationselementen, von denen ich hoffe, dass sie irgendjemand nutzen könnten.
Die kleinen Dinge
#!/bin/bash
#gestern zur gleichen zeit
date -d '1 day ago' +%FT%T
#vor einem Monat
date -d '1 month ago' +'%FT00:00:00'
#Monatsanfang
date +"%Y-%m-01"
#Zeit von CET in Z(Zulu = UTC+0) (Elli ...)
TZ=Z date +"%Y-%m-%dT%H:%M:00|%s" -d "22 Dec 2020 15:00 CET"
#Heute in Elli
today=$(LC_ALL=en_EN.utf8 date +"%d. %b %Y,")
#Gestern in Elli
yesterday=$(LC_ALL=en_EN.utf8 date --date "1 day ago" +"%d. %b %Y,")
#Vorgestern in 12 Wochen - Impfabstand für astrazeneca 
date -d "-2 day +12 weeks"


Dateien mit zufälligen Daten
Erzeugen Sie 50000 Dateien mit jeweils 1000000 zufälligen, druckbaren Zeichen in Zeilen von maximal 60 Zeichen Breite.
#!/bin/bash
for i in {00001..50000}; do 
  tr -dc "[:alnum:]" </dev/urandom | 
    head -c1000000 |
    fold -w60 >/tmp/file$i 
done 
tr -dc ... löscht alles außer der angegebenen Zeichenklasse.
</dev/urandom leitet die Eingabe aus dem Pseudozufalls-Device um.
{00001..50000} produziert die Zahlen in dem Bereich mit führenden Nullen.
head -c... schneidet die ersten Character heraus.
fold -w60 bricht Zeilen nach maximal 60 Charactern um.
Hashwerte erzeugen
Erzeugen Sie für die 50000 Dateien Hashwerte und schreiben Sie sie in eine Datei.
#!/bin/bash
for i in {00001..50000}; do 
  md5sum /tmp/file$i
done > /tmp/hashes
Oder einfach direkt in der Shell ohne Schleife:
find /tmp/ -name 'file*' | xargs md5sum > /tmp/hashes
LaTeX Snippets einbinden
In der Hauptdatei doc.tex:
\documentclass{scrartcl}
\newcommand{\vorname}{NIX}
\begin{document}
  \input{datafile}
  Der Wert dieses Datensatzes: \vorname
\end{document}
Und in der Datei datafile.tex:
\renewcommand{\vorname}{Oliver}
Kleine Vim-Tips
Wenn Sie in Ihre .vimrc die Zeile
:iab  dts strftime("%Y-%m-%d")
eintragen, koennen Sie im Text durch Tippen von
dts
das aktuelle Datum einfuegen.
oradfelder / 2017-04-05
Regular Expressions in der bash

Das ist der empfohlene Weg: Den regulären Ausdruck einer Variablen zuweisen und dann in doppelten eckigen Klammern ohne doppelte Anführungszeichen darauf zugreifen:

RE="^list|depl$"
[[ "$SSH_ORIGINAL_COMMAND" =~ $RE ]] || exit 1
Copy And Paste

Im Netz finden sich mancherlei Seiten, auf denen Kommandos zu markieren sind, um sie direkt in die Kommandozeile zu kopieren. Kopieren Sie einmal die folgende Zeile und pasten Sie sie in das Eingabefeld darunter.

echo cool stuff for lazy$(echo and stupid) admins

oder gleich in die Kommandozeile. Dass an der Stelle $(echo and stupid) genauso gut etwas sehr gefährliches stehen könnte, versteht sich von selbst. Also Obacht...

psql in der shell
 
   psql -t -AF $'\t' -c "select * from employees;" | \
     while IFS=$'\t' read a b c; do echo "$a,$b,$c"; done
  
Read Character by Character in bash

In der Bash kann mit $'\0' das Nullbyte ausgegeben werden. Als Delimiter bei *read* sorgt es dafür, dass auch Newlines und Tabs einzeln eingelesen werden. Mit "$'$CH" wird der Inhalt der Variablen wieder ausgegeben - und kann so an printf %d übergeben werden, damit der hexcode ausgegeben wird.


    echo -e "moin\nmoin\tmoin"| \
      while read  -d $'\0' -N1  CH ; do 
        echo "[$CH]"
        # printf "%d\n" "'$CH"; # als Integer (%x hex)
      done
    
Der korrekte Weg, mit der Bash Dateibäume einzulesen

Das Nullbyte und der Slash sind die einzigen Zeichen, die in einem Unix-Dateinamen nicht enthalten sein können. Der Befehl *find* traversiert das Dateisystem von dem ersten Argument aus - -print0 trennt die Namen dann mit dem Nullbyte.


  while IFS= read -r -d $'\0' file; do
    echo "$file"
  done < <(find . -print0)
    
Indirekte Variablen, Arrays und assoziative Arrays

Es gibt verschiedene Wege, mit indirekten Variablen umzugehen:

mykey=k456
declare index_$mykey=value123 # bash specific
eval "index_$mykey=value123"  # posix compatible
read index_$mykey <<<"value123"
printf -v index_$mykey "value123"               

eval "echo \$$index_$mykey"
refname=index_k456
echo ${!refname}              # indirect access

Sie werden insbesondere zu der eval-basierten Lösung harsche Kommentare im Netz finden ('eval is evil') - aber denken Sie selber nach, welche Risiken damit wann verbunden sind...

Oft ist es sinnvoller - so die Bash ab Version 4 verfügbar ist - mit Arrays oder assoziativen Arrays (Hashmaps) zu arbeiten:

declare -a myarray  #index array
for i in {0..9}; do
  myarray[$i]=value$i
done
myarray+=(dynamicappend)
for i in "${myarray[@]}"; do echo "$i"; done
echo "size: ${#myarray[@]}"


declare -A mykeystomyvalues  # associative array
mykeystomyvalues[a456]="maybeacomplexvalue"
echo ${mykeystomyvalues[a456]}
for v in "${mykeystomyvalues[@]}"; do echo value: "$v"; done
for k in "${!mykeystomyvalues[@]}"; do 
  echo key: "$k" value: "${mykeystomyvalues[$k]}"; 
done

Dazu kommt, dass indizierte Arrays in der Bash sparse strukturiert sind (anders als beispielsweise in Java): Das heisst,

num=$((2**63-1))
mykeys[$num]=myvalue
echo ${mykeys[$num]}

geht, ohne dass 2^63-1 Array-Elemente alloziert werden. Solange es sich also bei den Schlüsseln um Zahlenwerte handeln, verhalten sich indizierte Arrays in der Bash wie Hashmaps.