Befehlsreferenzen

Meine persönlichen Gedächtnisstützen der wichtigsten Werkzeuge ...


Top

bash

shopt -s extglob
shopt -u extglob

shopt -s globstar  
  ls **/*.jpg                             # Suche (auch) in Unterverzeichnissen
shopt -s dotglob                          
  ls *                                    # Anzeige (auch) versteckter Dateien (sonst ls .* noetig)
shopt -s nocaseglob

Reihenfolge
===========
  tilde-expansion
  variable-substitution
  command-substitution
  arithmetic expression
  word splitting of expanded text
  wildcard expansion
  command-lookup
 
# This does NOT work in the general case
$ files=$(ls ~/*.jpg); cp $files /backups/     <= Whitespace in Dateinamen moeglich
#
# This DOES work in the general case
$ files=(~/*.jpg); cp "${files[@]}" /backups/  <= 1.) globbing und 2.) escaped Array bewahren White-Spaces in Dateinamen
$ files=$(ls)    # BAD, BAD, BAD!              <= Whitespace in Dateinamen
$ files=($(ls))  # STILL BAD!
$ files=(*)      # Good!                       <= Globbing bewahret White-Space

eval ...  
printf "%10.10s\n" "$a" $b $c               # Quoting !
printf "%b\n" "Hello\nWorld"                # %b == %s mit Escape-Sequenzen
printf "%d\n" 011 0xff                      # oktal und hexadezimal
printf "%04d" 3                             # 0-Padding => 0003
printf "%-15s:\n" Hugo                      # flush left
printf "%Farbe: #%02x%02x%02x;\n" 66 43 171 # hexdezimal mit 0-Padding (%X ist Klein, %X Gross-Darstlelung)
printf "%10.2 f\n"                          # Laenge 10 inkl. Dezimaltrenner und 2 Nachkommastellen (!)
printf "%-10.5s:\n" Willibald               # 5 Zeichen mit Feldbreite 10 linksbuendig ausgeben => Willi    :
printf -v var "%04d" 5                      # 0005 => var
printf "%.5d\n" 5 => 00005
printf "%.4s\n" "string" => stri
printf "%${width}.${prec}f\n 14.7358
printf "%x %X" 15 15                        # f F


  

=========================================

Dezimale, oktale und hexadezimale Ausgabe
=========================================
  Hex => Oct
    printf "%o\n" 0x3a                      # => :
  Oct => Hex
    printf "%x\n" \072                      # => 3a  Octalwert MUSS 3-stellig sein
  Oct => Dec
    printf "%d\n" \072                      # => 58
  
  Oct => Char
    echo $'\72'                             # => :   Octalwert darf 1- bis 3-stellig sein
    echo $'\072'                            # => :
  Hex => Char
    echo $'\x3a'                            # => :

  Octal
    printf "\033"                           # => ESC

Screen als Canvas
=========================================
  printf "\033[%d;%dH" 10 10                # => Cursor an Position 10/10
  echo "Hello"

  alternativ

  cursMov=$'\e[%d;%dH'                      # \e == \033
  printf "$cursMov" 10 10
  echo "Hello"

  --------------------------------------------------------------------------
  #!/bin/bash

  # Variante 1: Escape-Sequences

  : <<EOF
  cu_row_col=$'\e[%d;%dH'
  cu_row_col=$'\033[%d;%dH'
  printf "$cu_row_col" ${2:-0} ${3:-0}
  # printf "\033[%d;%dH" 5 10
  echo "${1?}"
  EOF
  
  # Alternative: tput

  # tput setab 1
  # tput setaf 2
  tput cup ${2:-0} ${3:-0}
  echo "${1?}"
  --------------------------------------------------------------------------

Precision (Bedeutung)
=====================
printf "%.5d\n" 12345 => 123456           # keine Bedeutung, falls Zahl mehr Stellen als precision
printf "%.5d\n" 5 => 00005                # falls Zahl weniger Stellen als precision: Ausgabe von precision Stellen mit 0-padding
%s                                        # Maximalzahl an Zeichen
  %-5.4s                                  # 5 Stellen Feldbreite, maximal 4 Zeichen linksbuendig ausgeben
  %.4s                                    # maximal 4 Zeichen ausgeben
%f                                        # Zahl Dezimalstellen
Flags
=====
Space-Flag
  printf "% d\n" 15 -15                   # Positive Zahlen mit ' ', negative mit '-'
0-Flag
  printf "%05d\n" 15                      # 0-Padding => 00015
#-Flag                                    # Kennzeichnung von Oktal- und Hexadezimalzahlen
  printf "%x %#x" 15  15                  # => f 0xf
  
echo -n (kein Zeilenumbruch)
echo -e "Hello\nWorld\n"                    # Interpretation von Escape-Sequenzen
> file                                      # file leer anlegen/ueberschreiben
printf "%s Hugo\n" > file 2>&1
printf "%s Hugo\n" &> file                  # 1 und 2 umleiten (dito >&)
#-------------------------
exec 0<file                                 # dauerhafte Umleitung
exec 1>file                                 # dauerhafte Umleitung
  exec 5>&2                                 # Fehlerlausgabe (2) auf Ausgabe 5 "sichern" (=> 5 zeigt auf aktuelle Fehlerausgabe)
  exec 2> /tmp/hugo                         # Fehlerausgabe aendern
  exec 2>&5                                 # Fehlerausgabe "zuruecksichern" (2 zeigt auf aktuelles 5 == frueheres 2)
  exec 5>&-                                 # Sicherung loeschen (implizit 5 von 2 loesen)
#-------------------------
read a b c d                                # $d beinhaltet Rest der commandline
date=$(date)                                # == date=`date`
[ ]                                         # == test (builtin command (strings, integers und Dateiattribute), word splitting und file name expansion)
  [ "$var" -eq 0 ]
  [ "$str" != "string" ]
  [ -z "$str" ]
  
[[ ]]                                       # test inkl. regular expressions (not builtin command => parameter expansion ohne word spliting und file name expansion)

file="file name"                            # now word splitting
[[ -f $file ]] && echo "..."

[[ -f $file1 && ( -d $dir1 || -d $dir2 ) ]]        # Escape fuer Klammern nicht noetig
[ -f "$file1" -a \( -d "$dir1" -o -d "$dir2" \) ]

[[ "$hugo" = "string" ]]                    # Reiner String-Vergleich (da quoted right arguement)
[[ "$hugo" = pattern ]]                     # Cave: unquoted right argument => behandelt pattern analog "shopt -s extglob" wie auch case-statement, d.h. 
[[ "$string" == hugo@(willi|frank)th?o ]]   # das pattern muss den Vergleichs-String VOLLSTAENDIG abdecken
[[ "$hugo" =~ h[ae]inz ]]                   # extended regular expression (Muster muss string NICHT vollstaendig abdecken) gemaess "man regex 3"
[[ "$hugo" =~ "h[ae]inz" ]]                 # Cave: Muster ist reiner String 'h[ae]einz' (keine extended regular expression), muss Vergleichs-String jedoch NICHT vollstaendig abdecken
!= ist Negation zu =, ==

shopt -s extglob
[[ "$hugo" != +([0-9]) ]]                   # Keine Zahlen

while read line; do                         # cf. voriges Beispiel
  [[ "$line" =~ H[a-z]inz ]] && printf "Muster gefunden: %s\n" "$line"
  [[ "$line" =~ "H[a-z]inz" ]] && printf "String gefunden: %s\n" "$line"
done < <(echo -e "1. Heinz\n2. H[a-z]inz und Willi")

shopt -s extglob
echo ${*%%*(.gif|.jpg|.png)}

shopt -s extglob
array=($*)                                  # Cave: Trennung bei Whitespace innerhalb von Elementen aus $*
echo ${array[*]%%*(.gif|.jpg|.png)}
#---------------------------------------------------------------------------------------------------------------------
shopt -s extglob
pattern=0.00000                              # 5 Nachkommastellen
case $pattern in
  *0[.]00000*([^0])) echo "Fein" ;;          # Test auf nicht mehr als 5 Nachkommanullen
                  *) echo "Unfein" ;;
esac
#---------------------------------------------------------------------------------------------------------------------
datum=01.01.2022
datum=2022.01.01
datum=01.01.22
datum=22.01.01

if [[ "$datum" =~ ^[0-9]{2,4}[^0-9][0-9]{2}[^0-9][0-9]{2,4}$ ]]; then
  printf "Fein\n"
else
  printf "Unfein\n"
fi
#----------------------------------------
# In while-condition mit mehreren 
# Bedingungen 
#   falls auf einer Zeile => durch ';'
#   zu trennen
# ist nur deren letzte
# als Schleifenbedingung massgeblich
# while <list>; do
#   <list>
# done
# 
# Eine Zuweisung vor der Schleifen-
# bedingung auf derselben Zeile 
# muss NICHT durch ';' # getrennt werden
#----------------------------------------
declare -i i=0 max=10
while (( i++ )); [ "$i" -lt "$max" ]; do    # Nur letzte Anweidung ist Schleifenbedingung
  echo "i: $i ($max)"
done
#----------------------------------------   # read in eine Variable trimmt leading und trailing whitespace
while read var; do
  printf "%s\n" $var
done < <(cat << EOF
  Hugo   Willi   Franz      
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^               # <= Whitespace
EOF
)

=>

Hugo   Willi   Franz
^^^^^^^^^^^^^^^^^^^^                        # kein Whitespace
#----------------------------------------
tr -s ' ' ' ' < file                        # '-s' ersetzt eine "sequence" des Folgezeichens in Eingabe => Kompression von Blanks
#----------------------------------------

((...)) oder $((...))                       # $((...)) Posix ... ((...)) nicht Posix
if ((flag)); then ...; fi                   # Integer als true/false
(( var )) && ...                            # Test auf non-zero
test $(( a - 2 )) -ne 0                     # Arithmetik: Variablen muessen nicht dereferenziert werden
((abs = (a >= 0) ? a : -a))                 # Ternary verfuegbar
let a='(5+2)*3'                             # bei 'let' Klammern quoten
for ((i=1; i<=$1; i++)); do echo $i; done
if (( total > max )); then                  # da kein builtin sondern shell-syntax, werden '<>' nicht als redirection interpretiert

Listen:                                     # Exit-code = Exit-code des letzten statements
  <command>;<command>;...
  <command> && <command> ...
    grep -q goodword "$file" && ! grep -q badword "$file" && rm "$file"
    grep -q goodword "$file" && ! grep -q badword "$file" && { rm "$file" || echo "Couldn't delete: $file" >&2; }   # Cave: Semikolon vor schliessender Klammer
  <command> <newline>
  <command>
case-statement                              # Pattern analog pathname-expansion mit wildcards, character lists und ranges 
  case $1 in                                # Substring-Test (schnell)
    *"$2"*) true ;;
         *) false ;;
  esac
  case $1 in                                # Integer-Test
    *[!0-9]*) false ;;
           *) true ;;
  esac
break 2                                     # zweite Schleife von innen verlassen
printf "%s" "$@"                            # Einzel-Quoting aller Parameter
printf "%s" $@                              # Word-Splitting
printf "%s" "$*"                            # Gesamt-Quoting des Parameter-String
{01..10..2}
{a..z..2}
a*b?[[:lower:]][h-o]                        # Pathname-Expansion (unquoted ?*[] treated as file globbing parameters)
[[:upper:]][[:lower:]]                      # Gross-, gefolgt von Kleinbuchstabe
#-------------------
while read file; do
  ...
done < <(ls *.jpg)                          # Process substitution
#-------------------
while getopts "hx:" opt;do
  case $opt in
    h) puts "help" ; exit;;
    x) var="$OPTARG" ;;
  esac
done
#-------------------
Subshell ()                                 # erzeugt neuen Prozess
  $(...)                                    # command substitution
  | ...                                     # pipelines
  ( <command> )                             # Befehle in '()'
  prog() (....)                             # Funktion in Subshell

  tar -cf - . | (cd /newdir; tar -xpf -)    # tar aktuellen Verzeichnisses => stdout | subshell: cd und tar-Extraktion von stdin
                                            # Cave: Da Subshell kein Verzeichniswechsel für Haupt-Shell !
Code-Block {}                               # kein neuer Prozess <=> Subshell
  cd dir || {
    ...
  }
Command-Group
  { ls ...; cd ...; cat ...; } >out 2>&1                                              # Cave: ';' auch nach letztem (!) Kommando, sonst wird '}' als Argument desselben interpretiert
  [[ -f $CONFIGFILE ]] || { echo "Config file $CONFIGFILE not found" >&2; exit 1; }   # Cave: 'exit 1' wuerde in Subshell nicht die aufrufende Shell beenden
  {
      read firstLine
      read secondLine
      while read otherLine; do
          something
      done
  } < file


Parameter Expansion
===================
${var:-alternative}                         # falls var nicht gesetzt oder leer => alternative
${var-alternative}                          # falls var nicht gesetzt           => alternative
${var:=default}                             # ggf. Zuweisung
${var:+default}                             # falls var gesetzt und nicht leer  => default
for token in a b c; do
  var="${var:+"$var "}$token"
done
${var:?Variable ist leer}                   # Fehlermeldung
${#var}                                     # Laenge der Variablen
${var%.*}                                   # Endung beschneiden
${file##*/}                                 # Pfad abschneiden
printf "%s\n" ${passwd//?/*}                # Passwort verschleiern
file=${file//+( )/_}                        # shopt -s extglob: Alle Blankfolgen durch '_' ersetzen
printf "%s\n" ${passwd/[[:upper:]]/*}       # Ersetzung des ersten Grossbuchstabens
${var:2:2}                                  # offset und length
Pruefung von Variablen
=========================================
Falls in "prog":
  var={1:?}                                 
dann
  ./prog ""                                 # 1: Parameter ist Null oder nicht gesetzt
  ./prog                                    # 1: Parameter ist Null oder nicht gesetzt
Falls in "prog":
  var={1?}                                 
dann
  ./prog ""                                 # <alles ok>
  ./prog                                    # 1: Der Parameter ist nicht gesetzt
#---------------------------------          # dito fuer Arrays (offset bezeichnet Element mit diesem Offset, length die Anzahl Elemente ab diesem)
array = (one two three four)
${array[@]:1}                               # two
${array[@]:1:2}                             # two three
#---------------------------------
${!var}                                     # Dereferenzierung
${var^^}
${var^[h-k]}                                # Erstes Zeichen gross schreiben, sofern im Bereich h-k
${var,,[A-F]}                               # Alle Zeichen klein schreiben, sofern im Bereich A-F
$#                                          # number of positional parameters
#---------------------------------
array=( fifi lala huhu )
printf "%s\n" "${array[@]/%fi/bu}"          # Ersetzt in allen Elementen eine Nachsilbe fi => fibu lala huhu
printf "%s\n" "${array[@]//fi/}"            # Loescht in allen Elementen jeweils alle Vorkommen von "fi" => lala huhu
printf "%s\n" "${array[@]/%[iau]/}"         # Loescht in allen Elementen jeweils ein endstaendiges i,a oder u => fif lal huh
printf "%s\n" "${array[@]^^}"               # Konvertiert alle Elemente zu Uppercase
#---------------------------------
declare -A arr
#---------------------------------
for i in "${!assoc[@]}"                     # ${!assoc[@]}  <= Keys
do                                          # ${assoc[@]}   <= Values
  echo "key  : $i"
  echo "value: ${assoc[$i]}"
done
#---------------------------------
while IFS=':' read file category; do                 # Assoziativer Array eines dynamischen Arrays
  if [[ ! "${catA[*]}" =~ "$category" ]]; then       # Array to String => Test auf Membership (String( nicht Pattern-)-Match auf Teilstring)
    catA+=( "$category" )           
  fi
  eval ${category}+=\( \$file \)                     # dynamischer Array (Name resultiert aus Variable)
  fileA+=( $file )                  
done < "$config"
#- - - - - - - - - - - - - - - - -
for category in "${catA[@]}"; do    
  eval array=( \"\${${category}[@]}\" )              # String to Array
  for file in "${array[@]}"; do
    printf "%20.20s => %s\n" "$category" "$file"
  done
done
#---------------------------------
arr=( a b c )
arr+=( d )
${arr[0]}
printf "%s\n" "${arr[*]}"                   # quoted "*" => ein String
printf "%s\n" "${arr[@]}"                   # quoted "@" => jeder Parameter wird ein String
printf "%s\n" ${arr[@]}                     # unquoted @ (oder *) => Word Splitting ueber alle Parameter
printf "%s\n" "${arr[@]:1:2}"               # Zweites und drittes Array-Element jeweils ohne Word-Split ausgeben
printf "%s\n" "${arr[@]:1}"                 # Alle Array-Elemente ab dem zweiten ohne Word-Split ausgeben
printf "%s\n" "${#arr[*]}"                  # Laenge des Arrays (* oder @)
printf "%s\n" "${#arr[2]}"                  # Laenge des dritten Elementes
case var in
  "" | *[!0-9.]* | *[!0-9]) ;;              # Leer oder (Nicht Zahl oder Punkt) oder keine Zahl am Ende
esac                                        # Cave: var muss vollstaendig durch Muster abgedeckt sein
set -- $2 $3 $1                             # Resortierung '--' beendet Optionsliste fuer set
set -- $name $dial $address
set -a                                      # '-'Kurzoption setzt eine Funktion (hier: Export aller folgenden Shell-Variablen)
set +a                                      # '+' == unset einer Funktion
set -o allexport                            # Langform des Exports folgender Shell-Variablen mit Option -o
set +o allexport                            # '+' == unset
set -x                                      # print commands after expansion before running them
set -v                                      # print commands verbatim
set -o vi                                   # vi-style behavior
result="$( ls )"                            # schlecht: Ausgabe durch command substitution variable zuweisen
usage(){
  printf "%s\n" ${var:-Kein Wert}
} > ${1:-/dev/filedescriptor}
declare -n name=${var:-Leer}                # Namensreferenz => name ist var
var+="a b c"                                # Konkatenierung (analog bei Array: arr=( a b ) arr+=( c d )
var=${var:0:$limit}
printf -v result "%c" "$var"                # Zuweisung des ersten Zeichens aus var an Variable result

tmp=${var#?}                                # erstes Zeichen abschneiden =>
res=${var%"$tmp"}                           # alles bis auf das erste Zeichen abschneiden
echo var | tr 'a-z' 'A-Z'

case var in
  y|Y) ... ;;
  [aA] ... ;;
esac

substr=${string:0:$(( $end - 2))}
rightspaces=${var##*[! ]}                   # Alles bis auf letzten Whitespace rechts abschneiden
leftspaces=${var%%[! ]*}                    # Alles vom ersten Non-Whitespace bis zum Ende abschneiden
#-------------------------
while read; do                              # => $REPLY
  ...
done < file
#-------------------------
while read a b c; do                        # c erhaelt Rest jeder eingelesenen Zeile
  ...
done < file
#-------------------------
while IFS=";" read surname prename          # Eine Zuweisung vor einem Befehl macht die Variable lokal bezueglich des Befehles
  ...                                       # Cave: Zuweisung vor builtin bleibt auch nach Beendigung des builtin gueltig
done < file
#-------------------------
while read line; do                         # Erst nach Einlesen der Zeile IFS veraendern ...
  IFS=\;
  set -- $line
  echo "$1 - $2 - $3"
  IFS=$'{ \t\n}'                            # und restaurieren
done < Hugo
#-------------------------
cat a.txt | tr 'aeiou' 'AEIOU' > out.txt
#-------------------------
{                                           # Gruppierung (nicht Sub-Shell)
  date
  cat report.txt
} | mail -s "Hugo" name@adress
#-------------------------
IFS=. read -ra ip_elements <<< "127.0.0.1"  # Here-String als Standardeingabe (Manual: "The word is expanded and supplied to the command on its standard input.")
#-------------------------
files=file1,file2,file3,file4
mapfile -t -d ',' filesArr <<< "$files"           # Cave: Here-String => haengt am "Dateiende", damit an file4 ein Newline an => 
mapfile -t -d ',' filesArr < <(echo -n "$files")  # besser: Ausgabe ohne Newline 
#-------------------------
if grep -q "txt" <<< "$VAR"                 # Here-String wird zu Standardeingabe
then   
   echo "$VAR contains the substring sequence \"txt\""
fi
while read element ; do
  echo "$element" 1>&2
done <<< $(echo ${ArrayVar[*]})             # Here-String 
#-------------------------
{                                           # Gruppierung mit Umleitung der Standardausgabe
  while IFS=":" read team lead rest; do     # Cave: IFS gilt hier nur fuer read !
    printf "%s\n" "$dashLine"
    printf "%30.30s: %-40.40s %s\n\n" "$team" "" "$lead"
    printf "%30.30s: %-40.40s %s\n\n" "Scope-ID" "Anteil" "Scope"
    IFS=":"
    read -a claimArr <<< "$rest"            # Zerlegung von $rest als Here-String
    for claim in "${claimArr[@]}"; do
      scopeId=${claim%|*}
      anteil=${claim#*|}
      printf "%30.30s: %-40.40s %s\n" "$scopeId" "$anteil" "${scopeHash[$scopeId]}"
    done
    IFS=" "
  done < $teamfile
} > $outfile
#-------------------------
cat "$@" | while IFS=";" read line; do 
  ... 
done                                        # Mehrere Dateien einlesen
#-------------------------
while IFS=";" read line; do
  ...
done < <(cat "$@")                          # dito via process-substitution
#-------------------------
IFS=";" read a b c d < $file                # Erste Zeile einlesen (Zuweisung vor command bewirkt Lokalitaet)
#-------------------------
{
  read line1
  read line2
} < $file
#-------------------------
for i in {1..4}; do
  read lines[${#lines[@]}]                  # ziemlich abgehoben (Index ist immer die aktuelle Zahl von Elementen des Array)
done < $file
#-------------------------
mapfile -t -n 4 lines < $file               # n 4 (4 Zeilen einlesen) t (trailing newline entfernen)
printf "%s\n" "${lines[@]}"
#-------------------------
read -a array -p "Bitte Werte eingeben"
printf "%s\n" "${array[@]}"
#-------------------------
for file in {a..z}$RANDOM; do               # besser als touch ...
  > $file
done
#-------------------------
cut -c 22-24 $file | head -n3
cut -d : -f 1,5 /etc/passwd
#-------------------------
names="Willi,Franz,Hugo"
IFS=","
arr=( $names )
printf "%s\n" ${arr[2]}                     # => Hugo
#-------------------------
set -- $var                                 # Word-Split => $1,$2,$3, ...
#-------------------------
Regex                                       # im unterschied zu file expansion
=====
.                                           # jedes Zeichen
*                                           # 0 oder beliebig viele des vorigen Zeichens
File expansion                              
==============
*                                           # matched keine dot-files
.*                                          # matched dot-files
#-------------------------
printf "%s\n" {1..10} | 
awk '
  { total+=1 ; }
  END { print total; }
'
#-------------------------
shopt -s extglob
  ?(heinz|franz)                            # ein oder kein
  *(heinz|franz)                            # kein oder beliebige
  +(heinz|franz)                            # ein oder beliebige
  @(heinz|franz)                            # entweder oder
  !([abc0-9]*)                              # weder noch (Cave: Muss im Gegensatz der vorigen (logischerweise) den gesamten Vergleichs-String abdecken !)
                                            # Cave: '*' ist hier beliebige Zeichenfolge (globbing), nicht "0 oder mehrere" (regex)
  ---- Beispiel -----
  shopt -s extglob

  for string in "abc" "bbc" "cbc" "dbc"; do
    case $string in
      !([ab]*)) printf "%s did not match a or b at beginning\n" "$string" ;;
             *) printf "%s did match a or b at beginning\n" "$string" ;;
    esac
  done

time <command>                              # Messung der Ausfuehrungszeit
#-------------------------
printf "%s\n" "hugo" "willi" | {            # common subshell
  <command>
  <command>
}
read -r                                     # backslash literally einlesen
#-------------------------
rest="hugo:willi:franz"
IFS=":"
read -a array <<< "$rest"
printf "Array-Element: %s\n" "${array[@]}"
#-------------------------
printf "%s " "a" "b" | {
  read -a arr                               # Array einlesen
  printf "%s\n" ${arr[1]}
}
#-------------------------
read -n 1 var                               # nur 1 Zeichen einlesen
read -s var                                 # Ausgabe der Eingabe unterdruecken (Passworte)
read -p "Eingabe: " var                     # Eingabeaufforderung
read -p "Weiter ? (j/n): " -s -n 1 var
read -t 2  var                              # Timeout 2 Sekunden


#-------------------------
string="hugo:willi:franz"
read -a array -d ':' <<< "$string"          # -d: read up to delimiter
printf "%s\n" "${array[@]}"

   => hugo
#-------------------------

select name in Hugo Franz Willi Exit; do
  case $name in
     Hugo) echo "..." ;;
    Franz) ... ;;
    Willi) ... ;;
     Exit) exit 0 ;;
        *) echo "Ungueltige Auswahl" ;;
  esac
done

#-------------------------
set -x                                      # Ausgabe der Verarbeitungsschritte
#-------------------------
eval "$(date "+year=%Y" month=%m day=%d")"  # funktioniert, da in date-Formatstring jeder Zusatztext erlaubt ist
#-------------------------
{
  echo "a"
  echo "b"
} > file                                    # gemeinsame Umleitung
#-------------------------
join file1 file2                            # Spaltenweise Zusammenfassung anhand gemeinsamen "Primaerschlussels"
#-------------------------
format -s ...                               # split long lines
format -w 60 ...                            # wrap bei 60 Spalten
#-------------------------
Druck
  lpr
  lpstat
  lpq
  lprm
  lpoptions
#-------------------------
export -p                                   # Ausgabe der Umgebung
#-------------------------
if [ -n "$a" -o -n "$b" ]                   # -a und -o sind Test-Operatoren
if [-n "$a" ] || [ -n "$b" ]                # || und && jedoch sind Shell-Operatoren
if [ "$a" = a ] || { [ "$b" = b ] && [ "$c" = c ];}; then ...   grouping mit abschliessendem ';' <= ';' wird sonst als Argument interpretiert
#-------------------------
cat << "EOF"                                # quoted => keine Variablen-Substitution
  $a                                        # $a wird nicht substituiert
EOF
#-------------------------
# falls noexpandtab gesetzt ist
cat <<-ENDE
       Hugo
       Willi
       ENDE
#-------------------------
for file in $(cd /dir; echo *.txt); do      # command-substitution
  diff /old/dir/$file $file
done | more

Fortgeschrittene Beispiele
==========================

${vec[@]^^[aeiou]} 
${vec[@]//[aeiou]}

---------------------------------------------------------------------------------------
Match-Groups
------------
string=franz_hugo_willi
[[ $string =~ (fritz|h(ug|ag)o)_willi ]]    # extended regular expression (man regex 3)
echo ${BASH_REMATCH[@]}

=> hugo_willi hugo ug

---------------------------------------------------------------------------------------
string=aabbbbycc
[[ $string =~ a{2}b{2,3}[xyz]c{1,2} ]]

for element in a b c d e; do
  list=${list:+$list,}$element
done

names=([0]="Bob" [1]="Peter" [20]="$USER" [21]="Big Bad John")  # sparse array
photos=(~/"My Photos"/*.jpg)                                    # globbing => array

birke=baum
arr=(birke fichte tanne)
declare -A assoc=([heinz]=breinlinger [ingrid]=daubechies)
${arr[@]^[ft]}
${arr[@]/fich}
${arr[@]//e/E}
${!arr[0]^^}
${assoc[@]^[td]}

# falls noexpandtab gesetzt ist
shopt -s extglob
set -x 
mapfile -t <<- ENDE
	Hugo1 Hugo2
	Willi1 Willi2
	ENDE
printf "%s\n" "${MAPFILE[@]}"                    # zeilenweise Ausgabe, da quoted
printf "%s\n" ${MAPFILE[@]}                      # wortweise Ausgabe, da unquoted
IFS="|"
read -a array <<- ENDE
	Hugo|Willi|Franz
	ENDE
printf "%s\n" "${array[@]}"                      # geaenderter internal field separator

# Anstelle IFS zu aendern, explizit einen delimiter setzen
file
----
  Hugo|Franz|Willi
  Markus|Dieter|Franz

mapfile -d '|' -t < file
printf "%s\n" "${MAPFILE[@]}"

  Hugo
  Franz
  Willi
  ....

------------------------------------------------------------------------------------------
cat <<EOF
  $Hugo
EOF
------------------------------------------------------------------------------------------
cat <<'EOF'                                      # keine Ersetzungen
  $Hugo
EOF
------------------------------------------------------------------------------------------
cat <<-EOF                       
      $Hugo                                      # Tab-Unterdrueckung
EOF
------------------------------------------------------------------------------------------
myfunction <<EOF                                 # Funktionsaufruf mit 2 Parametern
  param1
  param2
EOF
------------------------------------------------------------------------------------------
: <<'DISABLED'                                   # Pogramm-Code auskommentieren
  command
  command
DISABLED
------------------------------------------------------------------------------------------
command <<< $var                                 # Here-String => stdin fuer command

  cat <<< $var
  cat <<< 'Escaped variable $var'                # keine Ersetzungen
------------------------------------------------------------------------------------------
# command expansion mit awk
------------------------------------------------------------------------------------------
colLen=$(awk -F ';' '
 BEGIN{
   for(i=1;i<=130;i++){
     colLen[i]=0;
     OFS=";";
     rightMostCol=0;
   }
 }
 {
   #----------------------------------------------------------------------------
   # Maximale Feldzahl aktualieren
   #----------------------------------------------------------------------------
   if(NF > rightMostCol){
     rightMostCol=NF;
   }
   #----------------------------------------------------------------------------
   # Spaltenbreiten bestimmen
   #----------------------------------------------------------------------------
   for(i=1;i<=NF;i++){
     #--------------------------------------------------------------------------
     len=length($i);
     if(len > colLen[i]){
       colLen[i]=len;
     }
   }
   
 }
 END{
   for(i=1;i<=rightMostCol;i++){
     printf(" %s",colLen[i]);
   }
 }
' dummy.csv)

printf "Laenge: %s\n" "$colLen"

Top

vim

Zwischen Operator-Command und Move-Command ist Operator-Pending-Mode

=====================================
{command}{number} {text-object == movement-command}
{number}{command} {text-object == movement-command}

In ex-Mode wird Text mit Zeilenadressen bestimmt, in vi-Mode mit Text-Objekten/Movements

- Folding
    Interaktiv
      V (Visual) + <move>
      zf

    Ein Fold
      zo (open)
      zc (close)
      zf (create)
      zd (delete)

    Mehrere Folds
      zO (alle unterhalb Cursor oeffnen)
      zC (alle unter Cursor schliessen)
      zR (alle oeffnen)
      zM (alle schliessen)
      zD (alle unterhalb Cursor loeschen)
      zE alle Folds loeschen

    :1,5 fo(ld)

    :set foldmedthod = marker,manual,indent,syntax, ...
    :set foldmarker={{{{,}}}}

   Ansicht mit (manuell angelegten) Folds speichern
    :mkview
   Ansicht mit Folds laden
    :loadview

- Kleinbefehle
    . letzten Befehl wiederholen
    Ctrl-f,Ctrl-b,Ctrl-u,Ctrl-d (ganze, halbe Seite nach unten/oben)
    Ctrl-y,Ctrl-e  (1 Zeile weiter nach unten/oben)
    {,} next, previous paragraph
    z10l z10h  Bildschirm 10 Zeichen nach links/rechts
    zH  halben Bildschirm nach rechts
      z10h 10 Spalten nach rechts
    zL  halben Bildschirm nach links
      z17l 17 Spalten nach links
    Bildschirmspruenge
      H (igh)
      M (iddle)
      L (ow)
    z
    z.
    z-
    a,i,A,I,o,O
      10i-<ESC> (fuegt 10 '-' ein)
    H,M,L Cursor nach oben, Mitte, unten
      10H (10 Zeilen unterhalb Oberkante)
      5L  (5 Zeilen oberhalb Unterkante)
    h,10j,5k,3l
    80|   => Springe zu Spalte 80
    g0
    Im folgenden sind '/' und '?' fuer Vorwaerts/Rueckwaerts austauschbar
    ---------------------------------------------------------------------
      d/Hugo  (Loesche bis Hugo)
      c/Willi (Aendere bis Willi)
      y/Franz (Kopiere bis Franz)
      y?a (Kopiere rueckwaerts bis einschliesslich a)
    d- (Loesche bis Anfang der vorherigen Zeile)
    cG (Aendere bis Dateiende)
    dH (Loesche bis Oberkante Bildschirm)
    cn (Aendere bis zum naechten gefundenen Muster)
    "2p (2. Loeschung (in Buffer 2) rueckgaengig machen)
    "_daw  Aktuelles Wort in "blackhole" register speichern (== Loeschen ohne undo/redo)
      '_' ist blackhole-register
    "a7yy (7 Zeilen in Buffer a)
    "aP   (vor Cursor Buffer a einfuegen)
    "Ay)  (Bis Satzende an Buffer a anhaengen)
    G (Dateiende)
    4G (Gehe zu Zeile 4)
    % (Sprung zu korrespondierendem Klammerpaar)
    0,$      (zu Zeilenanfang/-ende)
    _ oder ^ (zu erstem Zeichen der Zeile)
    3yb oder y3b (3 Worte zurueck kopieren)
    5yl oder y5l (5 Zeichen zurueck kopieren)
    Ctrl-g (Dateistatus)
    "ayw
    "ap
    r,R
      10r- (ersetzt 10 Zeichen durch '-')
      Vr-  (ersetzt in visuell markierter Zeile alle Zeichen durch '-')
    yl Kopiere aktuelles Zeichen  
    y$ alles bis Zeilenende kopieren
    y0 dito bis Zeilenanfang und vor aktuellem Zeichen
    s (== cl)
      Ersetzt EIN Zeichen mit beliebig viel Text
    7s (ersetzt 7 Zeichen und entspricht daher praktisch R)
    d2w,d3h
    db
    d/letztes_Wort  (move ist ein Pattern)
    g modifiziert Folgebefehl
    -------------------------
      g-Ctrl-a
        Ctrl-a inkrementiert die erste Zahl einer Zeile
        Dies gilt auch in einem Mit Shift-v gewaehlten Bereich
        mit Modifier 'g' davor werden alle ersten Zahlen des Bereiches zum jeweils
        vorherigen, um 1 inkrementierten Wert !
          1   => 2
          1   => 3
          1   => 4
          1   => 5
          1   => 6
      gj,gk,g0,g$ (Navigation nicht nach Editor-, sondern Bildschirmzeilen)
      gUiW  (Uppercase inside Word (non-whitespace))
      gUE  (Grosschreibung bis Wortende (non-whitespace))
      gue  (Kleinschreibung bis Wortende)
      gUge (Grosschreibung zurueck bis Ende des letzten Wortes)
      guG (lowercase bis zum Ende des Dokumentes)
      gUG (uppercase ...)
      - undo
        Chunks werden mit jedem Wechsel von Normal- zu Insert-Mode festgelegt
        (zusaetzlich auch durch Pfeiltasten bei Navigation)
        u (undo)
        U (Undo gesamte Zeile, solange Cursor auf Zeile bleibt)
        Ctrl-r (redo)
      g~ Case-Wechsel
      gR (virtual replace mode => Tab als Folge von Blanks interpretieren)
    ~ Case-Wechsel
    30~ Case-Wechsel der naechsten 30 Zeichen
    > oder < oder =
    Ctrl-o und Ctrl-i (zwischen letzten Sprungmarken vor- und zuruecknavigieren)
      S. 138 "Practical Vim"
      :set suffixesadd+=.rb     (.rb in Liste automatischer Suffix-Ergaenzungen aufnehmen)
      falls Cursor auf Dateiname steht, z.B. file
      gf                 => Oeffne file.rb        (Mnemo: goto file, real g (== modify Folge-)Befehl f (== find) zu Datei anstelle Zeichen in Zeile)
      Ctrl-o             => Ruecksprung zu voriger Datei (aus welcher Absprung erfolgte)
      
    "ac2w (naechste 2 Worte aendern und Original in Register a)
    Visual Mode
      zeichenweise
        v
          viw (visual inside word)
          vaW (visual around non-whitespace)
      zeilenweise
        V
      spaltenweise
        Ctrl-v
          Aenderungen fuer weitere Zeilen werden nach <Esc> uebernommen
      o (springt an anderes Markierungs-Ende)
      Ctrl-g (toggled zwischen Visual- und Select-Mode (direktes Ueberschreiben analog Windows))
      gv (modified v): markiert zuletzt markierten Bereich erneut
      Vr- (ersetzt jedes Zeichen der Auswahl mit '-')
    Insert-Mode
      Ctrl-d (Auszug)
      Ctrl-t (Einzug)
      Ctrl-h (Zeichen loeschen)
      Ctrl-w (Wort zurueck loeschen)
      Ctrl-u (Bis Zeilenanfang loeschen)
      Ctrl-o (Wechsel zu Insert-Normal-Mode: Ein Schuss in Normal-Mode)
      Ctrl-r 0 Register 0 ausgeben
      Ctrl-r / letztes Suchfeld ausgeben
      Ctrl-r Ctrl-p 0 (dito, jedoch ohne Einrueckungen)
      Ctrl-r " unnamed register ausgeben
      Ctrl-r = 20 * 5 (Rechenergebnis einfuegen == numerisches Register ausgeben)
      Ctrl-v (Zeichen woertlich eingeben)
      Ctrl-v 065 (ga zeigt Codierung des aktuellen Zeichens an)
      Ctrl-v <Tab> (Tabulator ohne Expansion eingeben)
      Ctrl-v u{1234}
      Ctrl-k Digraph-Code (:digraph)

Markieren
  ma
  'a
  `a
  ``   Rueckkehr zu vorigem Absprungpunkt (Auto-Sprungmarke)
  ''   Rueckkehr zu voriger Absprungzeile (Auto-Sprungmarke)
  mA   Grossbuchstaben => Datei-uebergreifend == global mark


- Doppelbefehle sind Shortcuts und beziehen sich auf die aktuelle Zeile
    cc
    >>
    dd
    yy
    gUgU (oder gUU)

    xp (Tausch zweier Zeichen => "transpose" als Merkhilfe)
- Großbefehle sind ebenfalls Shortcuts und beziehen sich auf den Rest der Zeile oder die ganze Zeile
    C (Rest der Zeile) == c$
    D (Rest der Zeile) == d$
      2D 2 Zeilen loeschen
    Y (bezieht sich auf ganze Zeile)
      10Y 10 Zeilen kopieren
    S (bezieht sich auf ganze Zeile) 
      10S (substituiert 10 Zeilen)
    4J (4 Zeilen verbinden)
- Text-Objekte (i hier analog a: a(round) oder i(inside) )
  aW
  ap
  a) == ab
  a} == aB
  a]
  a>
  a'
  a"
  at (Tag)
- Suchen/Finden
    :s/Hugo/Willi/gc 
    => falls nun Ersetzung fuer ALLE Zeilen gewuenscht
      :%s//~/&                  Ersetzung des letzten Suchmusters duch letztes Ersetzungsmuster mit denselben Flags wie zuvor
      g&                        Kurzform des vorigen ("global alles gleich" oder "modifiziert dasselbe")

      :s/Hugo/Willi
      :&                        Wiederholung der letzten Substitution (fuer nun aktuelle Zeile), jedoch nicht den letzte Flags
      g&                        Wiederholung der letzten Substitution fuer alle Zeilen
      :&&                       Wiederholung der letzten Substitution mit den letzten Flags


    :vimgrep /hugo/g *.rb     Suche in allen *.rb-Dateien (und Editierung der Treffer)
    :set (no)hlsearch         Highlighting fuer Suchergebnisse an/aus
    :set (no)hls
    /,?
      /Hugo/e                 Cursor auf Ende des Treffers positionieren
    n,N
    gn,gN   visual mode fuer naechsten Treffer
    :%s/Burg/Berge/g
    /~ (Tilde ist letzter Ersetzungsusdruck) => Suche nach Berge 
    :cnext   naechster und
    :cprev   vorheriger Treffer
    f,F,t,T
    10,20g/Hugo/s/Franz/Willi/g
    *,# (Wort unter Cursor vorwaerts oder rueckwaerts)
    :set ignorecase
    :set smartcase
    /foo\C  case-sensitive search
    /Foo\c  case-insensitive search
    :s/Willi/Hugo/c (confirm)
      y,n,q(uit),l(ast),a(ll)
    Ctrl-e Bildschirm nach oben
    Ctrl-y Bildschirm nach unten
    Posix-Character-Classes
      [:alnum:],[:alpha:],[:blank:] (space und tab),[:digit:],[:space:] (Whitespace),[:lower:],[:upper:]
- Sessions
    :mksession ~/Downloads/Sitzung.txt
    vim -S ~/Downloads/Sitzung.txt
- Macro
    qa (in Register a speichern)
    qA (an Makro in Register a anhaengen)
    q  (Aufzeichnung beenden)
      => qaq (Register a loeschen)
    @a
    4@a (Makro aus a 4 mal anwenden)
    @@  (letztes Makro anwenden)
    Ctrl-V <move>:normal @a  (aus Visual-Mode in ex-mode und fuer markierten Bereich Makro aus a ausfuehren)
      auf diese Weise kann alternativ zu Ctrl-v spaltenweise editiert werden, indem die Editierung des
      Feldes in Spalte 1 aufgezeichnet und danach fuer weitere Zeilen wiederholt wird.
- Command-Line-History
    q:
- Search-History
    q/
- Filterung in vi-Mode
  ====================
  Cave: 
    2 Formen
      !<number><movement><command>
      <number>!<movement><command>
    Movement-Command nach '!' muss mehrere Zeilen umfassen und bezieht sich auf alle Zeilen von Anfang bis Ende der jeweiligen Zeile
      also nur moeglich: (),G,{},[],+,-
      Beispiel
        !10+ (naechste 10 Zeilen)
        10!+ (naechste 10 Zeilen)
    !! ist Abkuerzung fuer aktuelle Zeile
  !) <command> (bis ans naechste Satzende durch <command> filtern)
- Command-Line
    :edit! Datei neu editieren, alle Aenderungen implizit verwerfen,
    :set (no)wrap(margin)
    :set (no)number
    :set (no)hls Toggle Syntax-Highlighting-Suche
    :syntax on|off (Syntax-Highlighting)
    :shell
    Ctrl-f (Command-Line Window == History)
    Ctrl-z (Stop und Shell aufrufen => Beenden/Rueckkehr mit fg)
      dito
        :stop => wie Ctrl-Z 
    :!ls
    :r!ls  (Ausgabe von ls unterhalb Cursor einlesen)
    :7r!ls (dito unterhalb Zeile 7)
    :$!uptime (letzte Zeile durch Laufzeit ersetzen)
    :10,20! sort -t',' -k2
    :source hugo.vim (wenn hugo.vim ex-Befehle enthaelt)
    :buffers
    :jumps (=> Jump-List)
    :changes (=> Change-List)
    :w >> bestehende_Datei 
    :w %.new (Speichern in <aktuelle Datei>.new)
    Auch Datei-uebergreifend kopieren
      :10,20yank a
      <Datei-Wechsel>
      "ap
    :bnext,bprevious,bfirst,blast,bdelete (Nummer oder Name)
      :3,5 bdelete
    :buffer 2 Wechsel zu Buffer 1 (== zweiter editierter Datei)
    :n(ext) (naechste Datei editieren)
    :1,10# (Zeilennummer temporaer einblenden)
    :put (paste immer UNTER die aktuelle Zeile im Unterschied zu p !)
    :args
    :args *.rb (befuellt die Argument-Liste <=> Buffer-Liste jedoch davon unbeeinflusst) => nun moeglich
      :next
      :prev
      :first
      :last
      :argdo
      :qa(ll)!
      :wa(ll)!
      :argdo normal @a
        fuer alle Elemente der Argument-Liste Makro a ausfuehren
      :argdo write (== :wa)
    :e(dit)! Datei neu einlesen (== Aenderungen verwerfen)
    :e Hugo.txt (weitere Datei editieren)
      % ist aktuelle Datei
      # ist alternative Datei
    :buffer# (Wechsel zur jeweils anderen Datei)
    :r# Zweite Datei in erste einlesen

    Autocompletion
    ==============
      Ctrl-n  Autocompletion aus generic wordlist

      CTRL-x (gefolgt von CTRL-...) cf. Pocket Reference Seite 47
        Auswahl mit CTRL-n/-p/-y
        Abbuch mit CTRL-e (end)

        ... CTRL-n/-p        Suche in mit 'complete' festgelegten Quellen
                                complete-List: .,w,b,u,t,i
                                d.h. effektiv in vorherigen oder folgenden Zeilen des aktuellen Buffers "."
        ... CTRL-f           Autocompletion von Dateien mit Auswahl (in Insert-Mode)
        ... CTRL-d           Macros
        ... CTRL-k           Dictionary (nach via 'dictionary' festgelegter Liste)
                             In .vimrc: 
                               set complete+=k
                                 Autovervollstaendigung auch innerhalb von dictionaries (zusaetzlich zu ".,w,b,u,t,i")
                               set dictionary+=~/.vim/teams.dict
        ... CTRL-l           Zeile in vorherigem Text derselben Datei
        ... CTRL-s           Spelling, sofern 'spell' gesetzt ist
        ... CTRL-t           Thesaurus via 'thesaurus'
        Hugo Ctrl-X <Tab>
          Suche in Wortliste der aktuellen Datei nach Worten, welche mit Hugo beginnen fuer autocomplete
            Ctrl-n (next)
            Ctrl-p (previous)
            Ctrl-y (yes)
            Ctrl-e (end ohne Uebernahme)

        Trick:
          Ctrl-x Ctrl-k     Aufruf der Autocomplete-Liste
          Ctrl-p            Sprung eine Zeile vor erstem Element == aktuell editierte Zeile
            alternativ fuer Autocomplete-Liste des aktuellen Buffers anstelle des Dictionaries
              Ctrl-x Ctrl-n Ctrl-p  => Sprung ueber Liste (== editierte Zeile)
              Ctrl-x Ctrl-p Ctrl-n  => Sprung unter Liste (== editierte Zeile)
          Hugo              => Autofilerung der angezeigten Liste nach allen mit 'Hugo' beginnenden Eintraegen
                            => Eingabe mit fortlaufend aktualisiertem Autocomplete
                            cf. S. 238 "Practical Vim"

          Filename-completion
            :pwd    => aktuelles Verzeichnis
            :cd /usr/local/bin
            i my Ctrl-x Ctrl-f    => Dateiliste aus /usr/local/bin zur Auswahl fuer alle mit 'my' beginnenden Dateien
            :cd -                 => Rueckkehr zu urspruenglichem Verzeichnis (des aktuellen Buffers)
                                     analog 'cd -' in Shell (=> vorheriges Verzeichnis)

    :Explore,Vexplore,Sexplore,edit
      :Explore ~/Downloads
    :browse open
    :col Ctrl-d (Liste der Moeglichkeiten mit col...)
    :col <tab> (schrittweise durch Liste der Moeglichkeiten mit col...)
    :colorscheme Ctrl-d (Anzeige der Farbschemata)
    :Ctrl-r Ctrl-w (uebernimmt Wort unter Cursor auf Kommandozeile)
    :ls
       % ist aktueller Buffer
       # ist alternativer Buffer
    :tabnew,tabnext,tabprevious,tabmove N,tabclose,tabonly
       gt,gT,1gt,tabs,tabm 0
    :registers
    :10 (gehe zu Zeile 10)
    :10,20t.
    :1,7y
    :2,9p
    :.,/while/d (von aktueller Zeile bis Zeile mit Muster 'while' loeschen)
    :%y Alle Zeilen kopieren
    :100;+5p   (';' bewirkt relative Adressierung zu Anfangszeile, bzw. Anfangszeile wird zu aktueller Zeile => identisch zu 100,105p)
    :3,8j
    :10,20co17 == 10,20t17
    :10,20m.   (move statt copy)
    :17,19d
    :5,25 normal A; (am Zeilenende ';' anfuegen)
    :%normal yi"$p  (Kopiere in allen Zeilen innerhalb '"' und gib an Zeilenende aus)
    :% normal i//   (Allen Zeilen "//" vornstellen)
    :5,25g/Hugo/normal @a  (Macro aus Register a auf Zeilen in Range 5-25, welche Hugo beinhalten, anwenden)
    :v/href/d (reziprokes global: Alle Zeilen loeschen, welche nicht href beinhalten )
    :%s/Hugo/Willi/g
    :/<Start>/+1,/<End>/-1d     (Zeilen zwischen Mustern loeschen)
    :'<,'>   Range bei visueller Auswahl 
    :.,.+3p  aktuelle und 3 Folge-Zeilen ausgeben
    :'as/Hugo/Willi/g  in Range mit Markierung 'a' substituieren
    :5co0  (0 ist virtuelle Zeile oberhalb Datei => An Anfang kopieren)
    :'<'>t0  (Range an Anfang kopieren)
    :t. (Duplizierung)
    :%s/\v ...  (very magic == nur Buchstaben, Zahlen und '_' ohne Sonderbedeutung)
      Beispiel

      30.09.2021

        :2,41s/\v([0-9]{2})\.([0-9]{2}).([0-9]{4})/\3-\2-\1/

      =>

      2021-09-30

      Beispiel: Ersetzen eines 1000-Trennpunktes

        :%s/\v([0-9]+)\.([0-9]{3})/\1\2/g

    :10mark a
    :10;+10w >> Hugo.txt (Zeilen 10-20 an Hugo.txt anhaengen)
    :17r Hugo.txt (Hugo.txt nach Zeile 17 einlesen)
    :/Markierung/r Hugo.txt (Hugo.txt nach Zeile mit Muster "Markierung" einlesen)
    :%s/Hugo/"\1"/g
    :%s/\v([a-z]+)/"\1"/g   (Alle Worte in '"' setzen)
    :%s/\V ...  (very non-magic)
      "uY         Zeile in Register u speichern
      /\VCtrl-ru  non-magic-Suche nach Inhalt von Register u
    :%s//Willi nutzt letzes Suchmuster fuer Ersetzung
    :%s//<Ctrl-r 0>/g  letztes Suchmuster durch Inhalt des Registers 0 ueberall auf allen Zeilen ersetzen
    :%s//\=@a/g  dito, jedoch mit Macro aus Register a
    :%s//~/g letztes Suchmuster durch letztes Ersetzungsmuster auf allen Zeilen ueberall ersetzen
    :g//d  Alle Zeilen mit letztem Suchmuster loeschen
    :g/muster/w > Muster.txt Alle Zeilen mit Muster in Datei Muster.txt schreiben
    :g/Hugo/s/\(Willi\|Franz\)/"\1"/g  Auf allen Zeilen mit Hugo alle Vorkommen von Willi oder Franz in '"' setzen
    :g/\vHugo/s/(Willi|Franz)/"\1"/g   very-magic: Auf allen Zeilen mit Hugo alle Vorkommen von Willi oder Franz in '"' setzen
    :g/\vHugo/s/(Willi|Fr%(a|e)nz)/"\1"/g   very-magic: Auf allen Zeilen mit Hugo alle Vorkommen von Willi oder Franz oder Frenz in '"' setzen, dabei Klammer mit %(a|e) nicht zaehlen
    :v//d  invers zu vorigem => alle nicht dem vorigen Suchmuster entsprechenden Zeilen loeschen
    :g!//d analog :v//d
    :g/ToDo/yank A (Alle Zeilen mit ToDo in Register a verketten)
    :g/ToDo/t$ (Alle Zeilen mit ToDo ans Dateiende kopieren) 
    :g/{/ .+1,/}/-1 sort   (Cave: Blank nach erstem Suchmuster: Abschnitte zwischen '{}' sortieren)
       Fuer jede Zeile mit "{": Sortiere von "aktueller Zeile + 1" bis eine Zeile vor "}"
    :s/\v:[^:]+:/[&]/g     (very-magic: Alle in ':' eingeschlossenen Worte in '[]' einschliessen)
    :g/Syntax/.,/Syntax-Ende/-1 move /Parameters/-1 
      entspricht Muster :[range]g(lobal)/Pattern/ Command
          Pattern: /Syntax/
          Befehl:  .,/Syntax-Ende/-1 move /Parameters/-1
        Finde Zeilen mit /Syntax/ 
        Implizit: Setze Zeile als aktuelle Zeile '.'
        von dort bis Zeile vor Zeile mit /Syntax-Ende/
        verschiebe vor Zeile mit /Parameters/
    :g/>stream/ .+1,/endstream/-1 delete                     # Loeschen von Stream-Inhalten in PDF-Datei
    :g/Chapter/ .+2w >> Hugo.txt (Haenge die jeweils 2-te Zeile nach Zeile mit "Chapter" an Datei Hugo.txt)
      Zeile mit Muster wird implizit aktuelle Zeile '.'
    :/Anfang/,/Ende/g/Chapter/ .+2w >> Hugo.txt (Haenge die jeweils 2-te Zeile nach Zeile mit "Chapter" innerhalb des Ranges Anfang-Ende an Datei Hugo.txt)
    :/Anfang/,/Ende/g/Chapter/ .+2w >> Hugo.txt | .+1t$ (dito und kopiere die Folgezeile (also dritte Zeile nach Chapter-Zeile) ans Dateiende)
      vor '|' ist aktuelle Zeile die zweite Zeile nach Chapter-Zeile
    :g/Description/,/Parameters/-1d Alle Abschnitte von Description bis Zeile vor Parameters loeschen
    :g/.*/mo 0 (Zeilenfolge umdrehen)
    :g/^/mo 0  (Zeilenfolge umdrehen)
    :v/\v^[[:digit:]]+/mo $  very-magic: Alle Zeilen, welche nicht mit einer Zahl beginnen, ans Dateiende verschieben
    :g/\v^[^[:digit:]]/mo $  very-magic: Alle Zeilen, welche nicht mit einer Ziffer beginnen, ans Dateiende verschieben
    Quantifier (fuer nicht very-magic)
      \+   (1 oder mehrere)
      \=   (0 oder 1)
      \{1,4} (1 bis 4}

    Wiederholung von Befehlen mit g: (Learning the vi and vim editors)
    ================================
      Hintergrund: :[range]g(lobal){Muster}{Befehl} 
        Befehl muss sich nicht auf Trefferzeilen mit Muster beziehen !
      :1,10g/^/ 20,27co $ (Kopiere Zeilen 20-27 10 mal ans Dateiende)
- Muster
    <, > Word-Boundaries (zero-width-items)
    \_ vorangestellt bedeutet "inkl. Zeilenende"
      \_s+  (Whitespace inkl. Zeilenende)
    /\v<(\w+)\_s+\1>  very-magic-Suche nach doppelten Worten, durch Whitespace oder Zeilenende getrennt
    :s entspricht :s//~/  (letztes Suchmuster und letzter Ersetzungs-String)
    :s;/home/heinz;/home/anja;g  # ';' als Delimiter anstelle '/'
    Einfuegungen des substitute-commands (Replacement-String)
      \1 \2 \0 (gesamter Treffer)
        :10,20s/\v(that) or (this)/\u\2 or \u\1/g => This or That
      \t \r 
      & == \0 (gesamter Treffer)
        :%s/\v[[:alnum:]]+/\u&/g => very-magic: Kapitalisierung aller Wortanfaenge
        :%s/\v[[:alnum:]]+/\U&/g => very-magic: Kapitalisierung aller Worte
        :10,20s/.*/(&)/
      ~ vorheriges Ersetzungsmuster, d.h. Ersetzung durch Ersetzungs-String des vorherigen (!) Ersetzungsbefehls
        :s/her/their/g
        :s/his/~/g
      \= Ersetzung durch VIM-Script-Ausdruck
    %(..) zaehlt Klammer nicht mit fuer Back-References
      :%s/\v(%(And|D)rew) (Neill)/\2, \1/g  Vor- und Nachname vertauschen, wobei die innere Klammer nicht gezaehlt wird ('%' vorangestellt)
    Look-Ahead und -Behind
      /\v"\zs[^"]+\ze/  Suche nach Nicht-Anfuehrungszeichen innerhalb von '"' (zs: zero-start == look-behind   ze: zero-end == look-after)
- Fenster
  :set mouse=a (erlaubt Fensterunterteilungen per Maus zu aendern und Fenster per Maus zu aktivieren)
  :set iskeyword?    Werteliste fuer iskeyword anzeigen
  :split,vsplit <Datei>
  Ctrl-ws (== split)
  Ctrl-wv (== vsplit)
  Ctrl-w Ctrl-w
  Ctrl-w(hjkl)
  Ctrl-w <Pfeil>
  Groesse aendern
    Ctrl-w= (gleiche Hoehen und Breiten)
    Hoehe
      10 Ctrl-w _ (auf Hoehe 10 setzen)
      10 Ctrl-w - 
      20 Ctrl-w + 
      :res -10
      :res +10
      :res 10 (Hoehe AUF 10 setzen)
    Breite
      10 Ctrl-w | (AUF Breite 10 setzen)
      10 Ctrl-w <
      15 Ctrl-w >
      :vertical res 10
      :vertical res -10
      :vertical res +10

  :close (Ctrl-wc)
  :only (Ctrl-wo)
  :help window-moving
  :help window-resize
- Navigation
    w,e,E,W,ge,b,B
    iw,it,i",i{,ip
      dito mit aw,at, ...
    - z.B. daw, ciW
    +,- (Zu Anfang der naechsten, vorherigen Zeile)
    (,) (Anfang, Ende des aktuellen Satzes)
    {,} (Anfang, Ende des aktuellen Paragraphen)
- Arithmetik
   10 Ctrl-A
   20 Ctrl-X
   set nrformats-=octal (um aus 007 008 oder 006 zu machen; ist bereits Default)
- Register
    :register /    (Suchmusterregister anzeigen lassen)
    a-z ueberschreiben
    A-Z anhaengen
    _ (Black-Hole)
    " unnamed register (Default)
    = expression register
    : Letztes ex-command
    % aktuelle Datei
    # alternative Datei
    / letzes Suchmuster
    Ctrl-r
    ======
      Insert-Mode: Ctrl-r<register>  Register einfuegen
        Ctrl-r / letztes Suchfeld ausgeben
      Ex-Mode      :Ctrl-ra (Register a auf Command-Line einfuegen)   
        :Ctrl-r / letztes Suchfeld ausgeben

        "ayw                      yank word in Register a
        :%s/Ctrl-ra/Hugo/g        Ersetze Inhalt von Register ueberall global

      Ctrl-r= 10 * 20 (Arithmetik-Register einfuegen, d.h. Berechnungsergebnis ausgeben)
        Cave: Punkt verwenden fuer Gleitkommarechnung, sonst nur Integerrechnung 
          Ctrl-r=20.5*3.7    
      :let i=5
      Ctrl-r=i  Variable i ausgeben  


    * (Middle-Mouse-Clipboard) und 
    + (Clipboard)
      :set noautoindent (empfohlen)
      Cave: "+p unterdrueckt im Unterschied zu "*p autoindent und andere Optionen
    "*yW Rest-Wort in Clipboard
    "*yaW Gesamt-Wort in Clipboard
    "*p Clipboard ausgeben
- Syntax-Highlighting
  :syntax on
  :set syntax         (zeigt an, welches Highlightin genutzt wird)
  :set syntax=html    
  :set filetype=html  

  Ctrl-L              (Refresh Highlighting)

Iterierte Werte erzeugen
========================
  :let i=1
  qa
  I Ctrl-R=i <Return> ) <Esc>
  :let i=i+1 <Return>
  q
  <Zeilen markieren>
  :'<,'>:normal @a

     1)
     2)
     ...
     8)

Inhalte von Variablen anzeigen
==============================
2 Varianten
  
  :echo &<var>
  :set var?            

  Beispiele
    :set path?
    :echo &filetype
    :set filetype?
    :help runtimepath  => Muster/Variablen des Suchpfades
    :echo &runtimepath => Ausgabe des aktuellen Pfades
    :echo &filetype    => Dateityp der aktuellen Datei
    :echo &iskeyword
    :filetype          => Ausgabe der Status zu filetype detection, plugin, indent
                          betreffend die folgenden Einstellungen in .vimrc 

:set <option>!       '!' am Ende => toggle current setting
  :set ignorecase! 
:set <option>&       '&' am Ende => Default-Wert setzen

Spezifische Anweisungen fuer eigenen Dateityp
=============================================

.vimrc
  filetype on (Default)
  filetype plugin on
  filetype indent on
.vim/filetype.vim
  autocmd BufNewFile,BufRead *.dict set filetype=dictionary
Alternativ
  .vim/ftplugin/dictionary/hugo.vim
oder
  .vim/ftplugin/dictionary.vim
mit Inhalt z.B.
  set sw=8
  
Dictionary bekanntmachen und Wort-Trenner dafuer hinzufuegen (da sonst Umbruch an diesen Stellen)
=================================================================================================
.vimrc
  set complete+=k   Default: .,w,b,u,t,i   <= nun auch mit "k" fuer Dictionaries (Ctrlx Ctrl-k)
  set dictionary+=~/.vim/heinz.dict        
  set iskeyword+=-,/                       <= Erweiterung der Wortzeichen, falls "/" und "-" in Dictionary vorkommen
                                              Cave: Danach werden "-" und "/" als Wortbestandteile und nicht mehr als Worttrenner
                                              gewertet



Top

sc

Cave: Jede Zelle kann gleichzeitig sowohl ein Label/einen String ALS 
      auch einen numerischen Wert enthalten. In alle Zellen koennen
      "parallel" Strings und numerische Werte eingegeben werden.
      
      Dies ist wichtig bei @ext(se,e), 
      da 'e' (expression) ein numerischer Wert sein muss, welcher als Argument 
      fuer den Aufruf von 'se' (string expression == command-line) in einen 
      String gewandelt wird. Nicht moeglich ist daher, fuer 'e' auf den 
      Label-Teil einer Zelle zu verweisen !

Cave: In *.sc Dateien stehen die Kommandos fuer Zellen in der eigentlichen (Lang-)Form.
      Diese Form ist zu verwenden fuer
        Macros
          => *.sc-Dateien koennen als Macro-Dateien-/Vorlagen genutzt werden
          cf. die (nur in der Man-Page dokumentierten) Befehle
            R(un)
            A(utoexecute)
            D(efine)
        Definition von Funktionstasten <F2>, <F3>, ...
      Die in einer sc-Sitzung eingegeben Kurzformen sind Shortcuts, welche
      in den Eingabemodus wechseln und in diesen (transparent) die eigentliche Langform eingeben
        cf. Man-Page
          the single key commands are shortcuts which switch to input mode after first entering the beginning of the full command for you

Command-Line
============
Cave: -P behaelt Formatierungen NICHT bei
  sc -P A0:G20/A30 Datei.sc > Auszug_verschoben.sc
    Kopiert Range A0 bis G20 in neue Datei, jedoch beginnend in Feld A30 (cf. unten)
  sc -P A0:G20/A30 Datei.sc >> Vorhandene_Datei.sc
    dito, jedoch Verschmelzung mit anderer sc-Datei
  sc -v -P A0:M126 Datei.sc > Auszug_nur_mit_Werten.sc
    Kopiert Range A0 bis M126 und wandelt dabei alle Ausdruecke/Formeln in Werte 
  sc -v -P % Datei.sc > Auszug_Gesamtdatei_nur_mit_Werten.sc
    dito mit Pseudo-Range der Gesamtdatei
  sc -W A0:M126 Datei.sc > Bildschirm-Abbild.txt
    Erzeugt reine Textausgabe des angegebenen Ranges wie in sc-Sitzung auf dem Bildschirm dargestellt (also mit dortiger Formatierung)
  sc -W % Datei.sc > Gesamte_Datei_als_Bildschirmabbild.txt
    dito mit Pseudo-Range der Gesamtdatei

Zweite Datei laden
==================

M (Merge)
  => Eingabefeld oben links
  | sc -P %/A100 Hugo.sc
  piped/inkludiert den gesamten Inhalt aus Hugo.sc (Angabe % anstelle Ranges) ab Zelle A100 des aktuellen Dokumentes


Befehle
=======

<F1>  man sc
      cf. auch 
        fkey n = "command"

G(et database from file) <= aktuelle Datei wird ueberschrieben
M(erge database into current file)
  M /home/heinz/.scrc 
    laedt diese Datei hinzu
      Tipp: Vorher Ausschnitt und neuen Startpunkt der neu zu ladenden Datei festlegen mit
        sc -P A0:G50/A101 Datei_2.sc > Datei_2_Ausschnitt.sc
          Editieren und Zeilenbreiten (ggf. auch Farben) anpassen
        In Datei_1 (welche auf Zeile 99, also 2 Zeilen ueber dem neuen Startpunkt der Ausschnittdatei endet):
          M Datei_2_Ausschnitt.sc
$K$20 
  Zellangabe fix
P <Datei> Speichern
ZZ Speichern und verlassen
W <Datei> Speichern des Bildschirmabbildes
W "Hugo.txt" AL0:AV18  Speichern des Bildschirmabbildes eines Range
T => table-output gemaess Wert von tblstyle, z.B. CSV speichern mit ':'-Delimiter (cf. unten)
  Beispiel
    S
      set tblstyle=latex
    T "" E2:I7
      speichert Range E2:I7 mit Defaultnamen und Endung .latex
        Cave: Erster " wird von sc gesetzt, zweiter ist zu ergaenzen, danach <TAB> fuer Range-Eingabe
~/.scrc: Konfigurationsdatei
  Definition der Default-Dateiendungen uber
    scext
    ascext
    tbl0ext
    tlbext
    latexext
    slatexext
    texext

    Beispiel
    ========
      scext "sc"
      ascext "txt"
      tbl0ext "csv"
      tblext "tbl"
      latexext "latex"
      slatexext "slatex"
      texext "tex"
      set color
      #---------------------------------------------------------------------------
      # Nach Return zu Zelle darunter
      #  craction=1 nach unten
      #  craction=2 nach rechts
      #  ^t r <Pfeiltaste in gewuenschte Richtung>  => Toggle des Return-Verhaltens
      #---------------------------------------------------------------------------
      set craction=0
      format 5 = "0,.&"
      format 6 = "0,.& Eur"
      format 7 = "0,.& L"
      #---------------------------------------------------------------------------
      # Function Keys
      #   $$ ist die aktuelle Zelle => fuer Range-Angabe verdoppelt
      #---------------------------------------------------------------------------
      fkey 2 = "color $$:$$ 1"  # Zellfaerbung zuruecksetzen
      fkey 3 = "rightstring $$ = @ext(\"dateutils.ddiff \"#A1#\" \"#A2#\" #\",0)"
      #---------------------------------------------------------------------------
      # Alternative, wenn neg. Zahlen in Klammern dargestellt werden sollen
      #---------------------------------------------------------------------------
      # format 5 = "0,.& Eur;(0,.& Eur)"
      # format 6 = "0,.&;(0,.&)"
      #---------------------------------------------------------------------------
      # Farben
      #   Cave: color 2 ist Farbe fuer negative Zahlen, wenn deren Kennzeichnung mit
      #     ^TN
      #     S colorneg
      #   gesetzt ist
      #---------------------------------------------------------------------------
      color 1 = @black;@white
      color 2 = @yellow;@white
      color 3 = @blue;@white
      color 4 = @green;@white
      color 5 = @red;@white
      color 6 = @magenta;@white
      color 7 = @cyan;@white

Navigation
==========
  ^e(jklm) => zur naechsten (nicht-)leeren Zelle oben,unten,links,rechts
    je nachdem, ob die aktuelle Zelle leer oder nicht-leer ist
  0  erste Zelle der Reihe
  $  letzt Zelle der Reihe
  ^  Oberste Zeile
  #  Unterste Zeile
  j,k,l,m  == Pfeiltasten
  ^Y und ^E Bildschirm 1 Zeile nach unten, oben
  g B100 Gehe zu Zelle B100
  ^A => Gehe zu Zelle A0
  ^L Display neu aufbauen/Schirm neu zeichnen
     z.B. nach ^X zur Anzeige von Formeln in Zellen mit Ueberlapp in Nachbarzellen
  w analog vim => naechster Wortanfang (== naechste gueltige Zelle)
  b analog vim => dito vorherige gueltige Zelle

^t Toggle Options
   a automatische Neuberechnung
     => explizite Neuberechnung mit '@'
   C (toggle Color)
   N (toggle Color fuer negative Zahlen => Farbpaar 2)
   E (toggle Color fuer fehlerhafte Zellen)
   r <Pfeiltaste> (toggle Bewegung nach Return)
   c  Cell-Highlighting (Highlighting vs. <=) 
   s colorslop => String, welcher laenger als aktuelle Zelle ist, auch dann in Nachbarzelle ueberlappen, wenn diese anderem Farbrange angehoert
   n quick numeric entry (Eingabe von Zahlen ohne "=")
S Set Options => Menue oben; jedoch nur Teilauswahl der Optionen der Manpage, besser als Auswahl ist Direkteingabe
    locale # Tausendertrennzeichen und Dezimalpunkt (nicht ueber ~/.scrc zu erreichen :-/)
      Einstellung wird nicht in Datei gespeichert und ist daher nur temporaer, aber
        W <datei>
      uebernimmt die temporaeren locale-Formatierungen als Textdarstellung des aktuellen Bildschirmes
    color
    cslop (funktioniert scheinbar nicht als Eintrag in Konfigurationsdatei .scrc)
      Ueberlapp eines String in Nachbarzelle, welche anderem Farbrange angehoert
        Cave: Bei ^T S cslop
          wird in der Datei folgendes eingetragen
            set cslop tblstyle = latex color
    craction=0,1,2
    tblstyle=
      0                   <= entspricht CSV-Ausgabe mit ':'
        delimiter ':'   
      tbl
        delimiter ':'
      latex
        delimiter '&'
      slatex
        Scandinavian Latex
      tex
        delimiter '&'
      frame
        Framemaker
      
@  Neuberechnung (z.B. falls automatische Neuberechnung mit ^ta deaktiviert wurde)
mx Markiere Zelle durch Puffer x 
'x springt wieder zu Zelle (analog vim)
cx Kopiert zuvor mit mx markierte Zelle
c. Kopieren Range => Range: 
   c. <Target-Range-Angabe mit Cursor> <TAB> (Uebernahme markierten Target-Ranges) <TAB> <BACK> <Ueberschreiben> Angabe des Source-Range

"x Naechstes yank/delete/pull-Command in Buffer x
  "ary <rangeauswahl mit Pfeiltasten>
    Range in Buffer a kopieren
  "app
    zuvor in Buffer a kopierten Range ausgeben
      Achtung: Zellreferenzen werden NICHT aktualisiert im Unterschied zu 
        rc <dest> <src>
z<Ret> Zeile wird erste Zeile des Bildschirmes
z. Zeile wird mittlere Zeile des Bildschirmes
z| Spalte wird mittlere ...
zc Zelle wird Bildschirmzentrum
= Zahleneingabe
><\ Stringeingabe rechts, links, zentriert 
  mit '"' beginnen, Abschluss-'"' wird automatisch gesetzt
  Beginnt der String selbst mit '\' wird das folgende Zeichen als Fueller der Spalte verwendet
    >"\-   => "------"
    <"\-   => "------"
    \"\-   => "------"
    
    Cave: Hier muss das schliessende Hochkomma wegen des Whitespace manuell gesetzt werden
      >"\+ " => "+ + + + "
{|} String ausrichten links, rechts, zentriert
F Zelle formatieren (cf. auch rF unten)
  F A8:A8 "0.00 Eur"
  F A8:A8 ",0 Eur"  (mit Tausendertrennzeichen)
  F A8:D8 "0 %"
  F A8:D8 "0.0000"
  F D7 "0 m3"
  Es kann hier auch ein Range eingegeben werden
    F B4:B8 "#,0.& \Liter"
       zu lesen als
         Zahl vor Tausendertrennzeichen
         mit mindestens einer 0 vor dem Dezimaltrenner '.' und
         danach so viele Zeichen wie Zellvorgabe fuer Dezimalstellen
            0.01 ergibt (bei Zellvorgabe zweier Dezimalstellen) bei
              #,0.&  => 0.01
              #,.&   =>  .01
                .&   =>  .01
  # Zahl
  0 Zahl mit 0-Padding
  . Dezimalpunkt
  % Prozentzahl durch Multiplikation mit 100
      z.B. Eingabe
        = 0.025
        rF <Bereichsauswahl> <Tab>
        "0.00 %  (Formatierungsangabe mit %)
        => Anzeige: 2.5 %
  , Tausendtrenner
  & Nachkommastellen werden mit 0 aufgefuellt, bis Zellvorgabe fuer Dezimalstellen erreicht
  \ Quotierung des naechsten Zeichens
  ; Eingabe getrennter Formate fuer positive und negative Zahlen

  Datumsformatierungen mit den Symbolen aus 'man strftime' und vorangestelltem Ctrl-D, also etwa
    FCtrl-D%F => angezeigt als "^D%T" (z.B. fuer Inhalt =@dts(2021,12,31) => Ausgabe als 2021-12-31
    Cave: Formatierter Datumswert erscheint so immer linksbuendig, also besser so eingeben
          FCtrl-D    %F
          angezeigt als "^D    %F"
    sinnvoll in .scrc
      entweder
        fkey 5 = "fmt $$ \"^D%F\""
      oder mit der vorigen Anmerkung
        fkey 5 = "fmt $$ \"^D    %F\""
      Cave: CTRL-D muss in vim "verbatim" eingegeben werden via CTRL-V CTRL-D und erscheint dann in blauer Schrift als ^D
     

Datumsfunktionen
================

  Cave: Alle Datums-/Zeitfunktionen ausser @dts liefern numerische Werte
        => Bei @date String-Eingabe (<>\) fuehrendes, automatisch gesetztes '"' loeschen wie immer bei String-Formeln, da sonst literal interpretiert
          @date(@dts(2022,01,01),"%F") => 2022-01-01
            cf. man strftime fuer zulaessige %-Werte
  2022.01.01 wird als Schnelleingabemoeglichkeit konvertiert zu @dts(2022,01,01) (aber nur, wenn als Zahlenwert eingegeben !)
    =2022.01.01 => @dts(2022,01,01)
       zusaetzliche Belegung des Label-Feldes moeglich mit
         >"2022.01.01
       => kombiniert in Feld links oben: "2022.01.01" [@dts(2022,01,01)] (in Zelle dargestellt wird String, Epoc-Sekunden sind in numerischem Feld)
  Beispiele
    A0: =@dts(2022,1,1) => 1640991600
    A1: =@dts(2022,1,31) => 1643583600
    A2: =A1-A0           => 2592000
    A3: >@date(@dts(2022,1,1),"%F")  => 2022-01-01
    A4: >@date(@dts(2022,1,1)+A2,"%F") => 2022-01-31
    A5: =A2/(60*60*24) => 30 (Abstand in Tagen zwischen 01.01. und 31.12.2022) 
    B1: >@date(A1,"%F") => 2022-01-31 (Formatierungsfunktion)
    B1: F CTRL-D%F                    (implizite Formatierung als Datum 2022-01-31)
  Cave: Moeglich ist
    Schnelleingabe
      A0: =2022.01.01 => [@dts(2022,01,01)] mit Anzeige des numerischen Feldes in Epoc-Sekunden, z.B. 123456
      A0: >@date(A0,"%F") => >{@date(A0,"%F")} [123456]
          Formel aus numerischem Feld wird durch Epoc-Sekunden ersetzt, angezeigt wird der String 2022-01-01
      aber: anschliessende Aenderung des numerischen Feldes durch z.B.
          =2022.01.31 =>     >2022-01-01 [@dts[2022,01,31)]
            macht wiederum den String konstant (mit dem vorigen Wert), d.h. man kann nur in entweder dem
            numerischen oder Label-Feld eine Formel unterbringen. Diese wird sofort in Wert umgewandelt, sobald
            das jeweils andere Feld eine Formel erhaelt.

    
# konkateniert Strings
    A1#A2
    "Hugo "#B17
  
<>\"\- Fuegt durchgehende Linie in Zelle ein

Zr zap row
 6Zr  6 Zeilen ausblenden
Zc zap column
sr show row <Auswahl>
sc show column <Auswahl>

<Zahl>f Spalten formatieren (Breite, Dezimalstellen, Formatierungsnummer)
                      Pfeil links/rechts => Spaltenbreite  (alternativ: h,l)
                      Pfeil auf/ab       => Dezimalstellen (alternativ: j,k)
                      <Zahl>             => Formatnummer (cf. unten)
                      (h,j,k,l oder Pfeiltasten, numerische Tasten fuer Formatierungsnummer)
                                                 0 Fixed
                                                 1 scientific
                                                 2 engineering
                                                 3 dates (Jahr 2-stellig)
                                                 4 dates (Jahr 4-stellig)
                                                 5-9 eigene vordefinierte Formate (cf. f=<Zahl>)

<Zahl>f<Blank> wie oben, jedoch mit Editierung der Formatangaben in der obersten Zeile
f=<Zahl> Definition des Spaltenformates <Zahl>
         Formatierungsangaben wie unter F
           Beispiel: F "#,0.& \Eur" <RETURN>
           Tipp: Format kann nach Ctrl-C mit Shift-Ins eingefuegt werden 
         Beispiel: f= (Auswahlmenue 0-9 erscheint) 5 "#,0.& ;(#,0.&)"


^x Formeln aller Zellen anzeigen
^r Anzeige aller Zellen mit numerischen Werten OHNE Formeln
g H3  => "go" H3
e Zahl editieren
E String editieren
Zeilen- und Spaltenkommandes (optional: Zahlangabe vorher)
ir,ic (insert row, column)  
  4ic (4 Spalten einfuegen)
ar,ac (Aktuelle Zeile, Spalte kopieren "append") 
  5ar 5 mal die aktuelle Zeile kopieren
dr,dc Beispiel: 5dr
or,oc
dd Aktuelle Zeile loeschen
x  Aktuelle Zelle loeschen
yr,yc,yy (yank row, colum, cell   - Abfolge: yr => pr; yy => pp oder pf; yc => pc)
  2yr 2 Zeilen kopieren
   pr (vorige) 2 Zeilen einfuegen
  3yc 3 Spalten kopieren
   pc (vorige) 3 Spalten einfuegen
pr,pc,pp == pull row, colum, cell
      pC (wie pp, aber Aenderung der Zell-Referenzen)
      p. (wie pC, aber mit Cursor-Auswahl des Ziel-Ranges)
         => beliebig viele Kopien genau EINER Quell-Zelle in Ziel-Range
         Cave: Funktioniert nicht mit mehr als einer Quell-Zelle
         Beispiel 
           yy <Return>
           p. <Range mit Cursor markieren> <Return>
           => n Kopien der kopierten Zelle
      pm (mergen statt einfuegen)
         ueberschreibt in Zielzelle bei zuvor kopiertem String nur deren String-Wert,
         waehrend ein numerischer Wert in der Zielzelle beibehalten wird
      pf (genau und nur Formatierung mergen nach z.B. vorherigem yy)
         Cave: Farben gehoeren NICHT zur Formatierung
         Formatierung ist ein zuvor mit F oder rF gesetztes Format der Quellzelle/des Quell-Range
         die mit f festgelegte Formatierung der Quell-Spalte wird NICHT in die Ziel-Spalte uebertragen
      px (exchange Quelle (Delete-Buffer) und aktuelle Zelle)
      pp (paste)
         Cave: Zell-Referenzen werden NICHT updated => bei Zellbezuegen pC verwenden
vr,vc,vv Formeln in (je nach Ausgabeformat der Zelle(n)) Strings oder Zahlen wandeln
Zr,Zc,ZZ Ausblenden
sr,sc Einblenden

Range-Commands: links oben (in Zielrange) positioneren, Kommando eingeben, Range mit Pfeiltasten auswaehlen und <TAB>
Tipp: Anstelle Cursorbewegung oder expliziter Eingabe 'A10:A40' koennen auch Wiederholung und Richtung angegeben werden (10j, 5l, 3h, ...)
      Beispiel: rf 10l <TAB> 10 1 <RETURN>
         range fill => 10 Zellen ab 10, inkrementiert um 1
      Beispiel: rf 10l <TAB> Hugo 0 <RETURN>
         increment '0' bewirkt Fuellung mit identischem Wert fuer alle Zellen
      Cave: Fuellt numerisches Feld, nicht Textfeld !

rx Range loeschen => p-Kommandos
ry Range yank (Referenzen fix) => p-Kommandos
     Range-Angabe ist der zu kopierende Range
       ry 5l
       ry <Cursor-Auswahl>
       ry <TAB> <BACKSPACE> <ueberschreiben>
rc Kopiere Destination-Range <= Source-Range
           Quelle kann einzelne Zelle sein => Range A2:A2

   Besonderheit: Zell-Bezuege werden aktualisiert (cf. pp vs. pC oben)

   Vorgehen
     aktuelle Zelle wird als destination range vorbelegt, destination range kann mit
       - Cursorbewegung <RETURN> 
     vergroessert werden
     Source-Range-Angabe danach mit
       - <TAB> <BACKSPACE> [ueberschreiben], z.B. <TAB><BACK> C4:H4 <RETURN>
rm fast wie rc, aber 'move'
   Vorgehen 1
     Links oben in Zielrange positionieren
     rm <Tab> <Tab>
     Ergaenzung des zweiten <TAB> mit Quellrange ueberschreiben (C17:C26) 
     <RETURN>
   Vorgehen 2 (optimal)
     Links oben in Zielrange positionieren
     rm (Target-Range (einzelnes Feld) wird eingetragen
     mit Cursor in erste Zelle des Quell-Range wechseln
     <TAB>
     mit Pfeiltasten Quell-Range markieren
     <Return>
     :-)
rr range-range (outrange und innerrange) => "freeze"
     outrange beinhaltet innerrange
     die "Differenz" wird nicht scrolled
     Auswahl der Range-Art mit Anfangsbuchstaben der Auswahlliste nach rr <TAB>
       hier: a(ll) auswaehlen oder l,t,r,b
     rr a(all) <TAB> A0:Z100 A1:Z100
       friert die oberste Zeile ein und erzeugt den Dateieintrag
         frame A0:Z100 A1:Z100
     rr l A0:Z100 1 
       friert die aeusserst linke Spalte ein
     Cave: "freeze" funktioniert nur, sofern bei Scroll der innere Range NICHT verlassen wird
           => immer Range definieren, welcher mehr Zellen umfasst als auf Bildschirm dargestellt
              einen outer-range A0:Z1000 kann man sich auch besser merken fuer unframe-command
rv Formeln in Zahlen wandeln
rd Range definieren (Bezeichner kann danach anstelle des Ranges verwendet werden)
   Cave: Zuvor mit ^T l Autolabelling disablen
     andernfalls wird Range-Name in (leere) Zelle links daneben geschrieben und in Datei als z.B.
       label C4 = "hugo"
     gespeichert
   rd "Wartung" AB10:AF73
   rd "Wartung"<TAB> <Range-Auswahl mit Cursor-Tasten>
     g "Wartung" => AB10
     rc F17 Wartung
   Ranges werden in Datei gespeichert als
     define ...
ru Rangedefinition loeschen
rs Sortieren mit Angabe von 3 Parametern 
     Cave: Sortiert werden kann nur die Zeilenabfolge
   Vorgehen
     Links oben im Range positionieren
     rs (ggf. mit Pfeiltasten markieren und) <Tab> 
     Rangeangabe vervollstaendigen (eintippen, springen oder mit Pfeiltasten markieren)
     optional: Sortieranweisungen in "..." eingeschlossen (auch mehrere Spalten nacheinander)
       1.) + oder -
       2.) # oder $ (# fuer numerisch, $ fuer String)
       3.) <Spalte innerhalb Range, nach welcher sortiert wird>

       Default ist "+$", also alphabetisch aufsteigend

       Beispiel: 
         rs <Pfeiltasten Range markieren> <Tab> "-$A" <RETURN>
         rs <Tab><BACK> A1:D10 "+#B" <RETURN>
         rs <TAB><BACK> A1:A10 <RETURN>
         rs <TAB><BACK> A1:D10 "-$A+#B" 
           zuerst alphabetisch absteigend nach A
           danach numerisch aufsteigend nach B
         rs <TAB><BACK> A1:D10 "+$A+#A" 
           entweder alphabetisch oder numerisch aufsteigend in A

rf Range fuellen
   Vorgehen
   rf
   Range mit Navigationstasten markieren
   <TAB>
   Startwert
   Inkrement
   <RETURN>
   Beispiel: 
     rf <Pfeiltasten> <Tab> 10 5 <Return>
     rf 10j <Tab> 10 5 <RETURN>
r{ Range ausrichten
r}
r|
rS Rangedefinitionen anzeigen (z.B. auch Farbwerte)
rF Range formatieren
   Rangeauswahl mit Pfeiltasten
   <Tab>
   Formatangaben wie unter F

   Beispiel: rF <Pfeiltasten> <Tab> "#,0.& \Eur" <RETURN>
   Tipp: Format kann nach Ctrl-C mit Shift-Ins eingefuegt werden 

rC Farbrange anlegen
   Rangeauwahl wie immer (Links oben positionieren, Pfeiltasten, <TAB>)
   gefolgt von Farbnummer (1-8) und
   <RETURN>
rd Range definieren
   rd "Name" <TAB> Cursor bewegen oder Range eingeben (Backspace + Ueberschreiben)
   g <Name> springt zu definiertem Range
rS Range-(und andere) Definitionen anzeigen
ru Range entdefinieren
   ru "Name"

Farben
  rS u.a. alle Farbdefinitionen anzeigen
  1 ist immer Defaultfarbpaar
  2 Farbe fuer negative Zahlen, wenn colorneg gesetzt
    S colorneg oder
    ^TN
  3 Farbe fuer fehlerhafte Zellen
    S colorerr
    ^TE
  4 Farbe fuer Felder mit Notizverweisen
  C Farbdefinition fuer Auswahl aus 1-8 setzen
    ohne Formatangabe => loeschen der Farbdefinition
    Formatangabe: @white;@green (Vordergrund und Hintergrund)
    falls bereits Format definiert war, wird dieses zur Editierung angezeigt
    Defaultfarben
      color 1 = @white;@blue
      color 2 = @red;@blue
      color 3 = @white;@red
      color 4 = @black;@yellow
      color 5 = @black;@cyan
      color 6 = @red;@cyan
      color 7 = @white;@black
      color 8 = @red;@black
Notizen
*a legt Link zu Zielzelle (mit Kommentar an)
   Angabe der Zielzelle wie immer mit <TAB> <TAB> <BACK> Ueberschreiben
     Cave: Ist das Feld numerisch, wird ein * als Kommentarkennzeichen in Farbe 4 vorangestellt
** springt zu Zelle mit Kommentartext
'' Ruecksprung zu Ausgangszelle
*d Kommentarverweis loeschen
*s zeigt Zellen mit Kommentarverweis durch Kontrastfarbe

Funktionen/Formeln
==================
  Fuer alle elementar und wichtig:
    ~e ist Verneinung eines Ausdruckes e
    Elemente einer Formel koennen entweder Strings oder numerische Werte sein
      demgemaess muessen Werte und Zellbezuege innerhalb von Formeln ggf. zu Strings oder numerischen Werte gewandelt werden
        @ston(A17)
        @fmt("%.sf",B101)
    Das Ergebnis einer Formel kann entweder ein String oder numerischer Wert sein
      demgemaess muss bereits die Formel selbst entweder als numerischer Wert oder String eingegeben werden
        =@if(....)  => Ausgabe in numerisches Feld der Zelle
        >@if(...)    => Ausgabe in String-Feld der Zelle
          Damit die Formel selbst als solche und nicht Text interpretiert wird, muss das von sc automatisch zu Beginn
          der String-Eingabe eingefuegte Hochkomma zunaechst geloescht werden, also
            @if(...) 
          und nicht
            "@if(...)
        >@sval("D",0)  => Uebernahme des Labels aus D0
          und nicht >"@sval("D",0)

  @sum
  ====
    Bedingte Summierung (wie auch andere bedingte Funkionen)
      Falls der Bedingungsausdruck sich auf eine andere Spalte bezieht, wird genau und nur deren oberste Vergleichszelle angegeben.
      Die untere Vergleichszelle ergibt sich aus der Summationsspalte
    @sum(A0:A3)                  <= unbedingte Summation von A0 bis A3
    @sum(A0:A3,@eqs(B0,"ja"))    <= bedingte Summation   von A0 bis A3, sofern Bedingung jeweils in B0 bis B3 erfuellt ist
    @sum(A0:A3,~@eqs(B0,"ja"))   <= bedingte Summation mit Verneinung ('~' ist boolsches Nein)

       A             B
    0  1.0                        <- Beginn der bedingten und unbedingten Summation
    1  2.0           "ja"
    2  3.0           "ja"
    3  4.0                        <- Ende der bedingten und unbedingten Summation
    4  5.0           "ja"         <- wird nicht mehr bedingt summiert
    5
    6  =@sum(A0:A3)  =@sum(A0:A3,@eqs(B0,"ja"))

  =>   9             5 

  A7: 10.5
  Eingabe: >@fmt("zu viel %10.2f",A7)  => "zu viel     10.5"
    Cave: Eingabe mit ">", da String-Funktion

  @sum(A0:A9,A0>5)
  @sum(A0:A9,A0=5)    numeric equality <=> @eqs(A0,"ok") string equality
    summiert alle Zellen von A0 bis A9, welche jeweils (!) groesser/gleich 5 sind


  Externe Funktionen
  ==================
    @ext(se,e) 
      se=string expression
       e=(numerical) expression

      se: Erster Teil der Kommandozeile: muss String oder Verkettung von Strings sein (oder Bezug auf String-Wert einer Zelle)
            
       e: Zweiter Teil der Kommandozeile: muss numerischer Wert sein (oder Bezug auf numerischen Wert einer Zelle) und wird implizit zu String gewandelt
          Cave: Dennoch ist NICHT moeglich, gleich einen String anzugeben oder auf den String-Wert einer Zelle zu verweisen

      Der Trick ist daher, den gesamten Aufruf in Teil 1 als Verkettung von Strings zu verpacken und diese Kommandozeile mit
      dem Bash-Kommentarzeichen '#' so abzuschliessen, dass Teil 2 nur als Kommentar in den Gesamtaufruf kommt
      (cf. hierzu auch 'man sc')

      Cave: Das Konkatenierungszeichen fuer sc ist ebenfalls ein '#' ;-)

      Beispiele
      =========

        Beispiel 1
        ==========
        Konkatenierung von Strings

        #######################Externe Funktion ist ein Bash-Script###############################
        #!/bin/bash
        #-------------------------------------------------------------
        # Test-Script mytest
        #-------------------------------------------------------------
        printf "Arg1: (%s) Arg2: (%s)\n" "$@"
        #######################Externe Funktion Ende##############################################

        Cave: Im folgenden ist '#' das sc-Konkatenierungszeichen UND das Bash-Kommentarzeichen vor dem damit auskommentierten zweiten Teil der Kommandozeile '0'
        Cave: Das Ergebnis von @ext ist wiederum ein String, KEINE Zahl !
              Anschliessend daher mit @ston in Zahl wandeln (wenn mit dem Ergebnis weitergerechnet werden soll)
              Cave: Wandlung in EINEM Schritt, d.h. Zahlausgabe in die Zelle mit der @ext-Formel, scheint nicht moeglich

             A            B              C                                                   D
        1    2021-01-01   2021-01-31     @ext("mytest "#A1#" "#B1#" #",0)                                            => Arg1: (2021-01-01) Arg2: (2021-01-31)
        2    2021-01-01   2021-06-31     @ext("dateutils.ddiff "#A2#" "#B2#" #",0)                                   => 180 (String)
        3    2021-01-01   2021-06-31     @ston(@ext("dateutils.ddiff "#A3#" "#B3#" #",0))    =@ston(C3)/2            => 180 (String) => 90 (Zahl)


        Beispiel 2
        ==========
        Konkatenierung von Strings und numerischen Werten

        #######################Externe Funktion ist ein Bash-Script###############################
        #!/bin/bash
        #-----------------------------------------------------------------------------------------
        # Externe Funktion fuer sc-Tabellenkalkulation: myscsollcell
        #-----------------------------------------------------------------------------------------

        . /usr/bin/common   # fuer Funktion 'calc'

        steuerKonto=$1
        buchung=$2

        if [[ "$steuerKonto" =~ ^[0-9]+$ ]]; then
          case "$steuerKonto" in
            1568) printf "%s\n" $(calc "$buchung / 1.05" 2 2) ;;
            1571) printf "%s\n" $(calc "$buchung / 1.07" 2 2) ;;
            1575) printf "%s\n" $(calc "$buchung / 1.16" 2 2) ;;
            1576) printf "%s\n" $(calc "$buchung / 1.19" 2 2) ;;
            1771|1773|1775|1776) printf "%s\n" $buchung ;;
            *) printf "%s\n" 0 ;;
          esac
        else
          printf "%s\n" 0
        fi
        #######################Externe Funktion Ende##############################################


           A         B            C
        0  Konto     Buchung     
        1  1568      100.0        @ext("myscsollcell "#A1#" "#@fmt("%.2f",B1)#" #",0)}           <= Verkettung wie in Beispiel 1, jedoch Wandlung von B1 in String => ergibt 95.23 (= 100.0/1.05)

                                                   
     Cave: Vor Duplizierung von @ext-Formeln
             mit (Toggle-Befehl)
               ^ta
             Auto-Aktualisierung ausschalten (sonst Core-Dump)
             rc-Befehl ausfuehren
             Ergebnis editieren
             mit
               @
             alle Berechnungen aktualisieren
             und Auto-Aktualsierung wieder einschalten

           Alternativen: Formel als Text kopieren mit STRG+SHIFT+C und wiederholt einfuegen mit SHIFT+EINF (und editieren)
             Cave: Vor Einfuegen in Eingabefeld links oben automatisch eingefuegtes '"' loeschen !
             Tipp: Text als Hotkey belegen (cf. unten)
               fkey 5 = "rightstring $$ = @ext(\"dateutils.ddiff \"#A1#\" \"#A2#\" #\",0)"

  @if-Anweisungen
  ===============

      Falls Stringausgabe:                                  
        Numerischer Vergleich
          @if(C126=100,"Dr. Breinlinger","Sonst jemand")   
        String-Vergleich
          @if(@eqs(C126,"Heinz")?"Dr. Breinlinger,"Sonst jemand")
      Falls numerische Ausgabe:  
        Numerischer Vergleich
          =@if(C126=100|C126=50,1,2)
        String-Vergleich
          =@if(@eqs(C17,"Passt"),1,2)

      Alternative via Operator e?e:e        @eqs(C126,"Heinz")|@eqs(C126,"Willi")?1:2

      Cave: Rekursionen sind nur durch Klammern des jeweils gesamten Else-Zweiges einer jeden Rekursion moeglich:

        Beispiel
        ========

        Falls Feld G304 die String-Werte "1568","1571","1575","1576" annimmt: Jeweils verschiedenen Berechnungen

                                       ( Else-Zweig 1                  ( Else-Zweig 2                  ( Else-Zweig 3                   )))
        @eqs(G303,"1568")?D4/1.05*0.05:(@eqs(G303,"1571")?D4/1.07*0.07:(@eqs(G303,"1575")?D4/1.16*0.16:(@eqs(G303,"1576")?D4/1.19*0.19:0)))


Programmierbare Funktionskeys
=============================

  fkey <nummer> = "command"
    in ~/.scrc oder *.sc oder auf command-line
      command ist (genau und nur) JEDE (!) Anweisung, wie sie auch in einer *.sc-Datei vorkommt
      $$ bezeichnet die aktuelle Zelle => fuer Range-Angabe also verdoppeln (A2 => A2:A2)

      Beispiele

        fkey 2 = "color $$:$$ 1"  <= "entfaerbt Zelle", sofern Farbe 1 schwarz/weiss darstellt
        fkey 9 = "fmt $$ \""0,.& Eur\""
        fkey 4 = "let $$ = @myrow"
        fkey 5 = "rightstring $$ = @ext(\"dateutils.ddiff \"#A1#\" \"#A2#\" #\",0)"
          => erzeugt natuerlich, so die Dummy-Zellwerte A1,A2 keinen Datums-String beinhalten, eine Fehlermeldung
             und ist nach Eingabe ueber <F5> schlicht mit E zu editieren :-)

Macros
======

cf. Anmerkungen zu Beginn

R *.sc-Datei
  fuehrt Befehle der eingelesenen *.sc-Datei aus

  R Macro.sc

A *.sc-Datei
  laedt *.sc-Datei bei naechstem Start der aktuellen Datei automatisch

  A Macro.sc

D <Macro-Verzeichnis>

  Definiere Verzeichnis fuer mit R oder A angegebene Macro-Dateien

Vermischtes
===========

CTRL-X zeigt alle Zellen mit numerischen Werten, welche aus Formeln resultieren
CTRL-R ist das genaue Gegenteil => Anzeige aller Zellen mit numerischen Werten OHNE Formeln
  => Anzeige aller in einem Formular AUSZUFUELLENDEN Zellen :-)

g <suchbegriff oder zelle>
  Cave: Alle in "" eingeschlossenen Suchbegriffe sind regular expressions
        Gesetzt werden muss wie immer nur der ersten '"'
  Cave: Pattern muessen nur Teil-String matchen
  Cave: Mustersuchen bei Zahlen mit
          g #"
        beziehen sich immer auf das dargestellte 
        Ergebnis, d.h. auch Formelergebnisse werden damit gefunden
  Cave: Mustersuchen mit
          g %"
        beziehen sich immer auf die Formeldarstellung
  Cave: Regulaere Ausdruecke immer analog ed (Vorlaufer vi(m)s)
  ========================================================================

  g a14 => Zelle mit Koordinaten
  g 10.7 => Zelle mit dieser Zahl 
    Cave: gesucht wird nach diesem Zahlwert, nicht einer formatierten Zahl-Darstellung
  g "Abschlaege    => Zelle mit diesem regulaeren Ausdruck
  g #"6,362 kg     => Suche nach formatierter Zahl (verstanden als regulaerer Ausdruck
                      der formatierten Zahldarstellung)
  g #".*15.*       => findet >2,150.43< ebenso wie >115.61 Eur/mon<
    Cave: g #"42"  => findet alle direkt eingegebenen oder errechneten Zahlen, welche
                      "42" ENTHALTEN !
    Cave: g #"2150 => findet mit Tausendertrenner dargestellte Zahl "2,150" NICHT
                      => es wird immer nach der FORMATIERTEN Darstellung gesucht
          g #".72  => sucht nicht nach <Komma>72, sondern 
                        beliebige Ziffer, gefolgt von 72
          g #"8.*% => findet z.B. '82 %','62.81 %",
  g %"T32          => Suche nach Zelle mit Formel, welche T32 beinhaltet (==referenziert)
  g %".*B.*"       => Suche nach Zellformeln, welche ein 'B' beinhalten
                      =B6
                      =12*B7
  g "^.*Vita.*$    => Suche mit regulaerem Ausdruck 
  n                => Wiederholung der Suche/nachesten Treffer anzeigen
  g<return>        => Widerholung der letzten Suche (analog n)

! <Return> => Shell beginnen .. Abschluss mit exit und "press any key to continue ..."
! ls       => Shell Befehl ausfuehren

psc (prepare (data for) sc)
===========================

Cave: Integer werden als Zahlen erkannt; Gleitkommazahlen nur, wenn Dezimaltrenner ein '.' 
ist (und andernfalls als String interpretiert).


dos2unix Master.csv
psc -C2 -k -d\; < Master.csv > Master.sc

    -C2 : Spaltenbreite 2 Stellen weiter als fuer breitesten Eintrag noetig
    -k  : keep all delimiters => leere Zellen nicht verwerfen
    -d\;: Delimiter ;

Alternative (mit automatischer Wandlung deutscher Gleitkommazahlen): mycsv2sc

Export zu csv
=============
  Export als csv-Tabelle mit (innerhalb sc-Sitzung)
    S tblstyle=0 
      als Default bereits eingestellt und als solches nicht in *.sc sichtbar 
      (jedoch aus .scrc uebernommen)
    T
      Export als Tabelle mit ':' als Trennzeichen

      dos2unix Export.csv
      vim Export.csv
        %s/:/;/g

Top

screen

Command-Line-Mode (analog ex)

C-a :
  resize -v + 20
    Vertikal plus 20 Zeilen
  resize =
    Gleiche Groesse aller Teilfenster


Detach/Reattach
===============
ssh heinz@nas
screen
Ctrl-A Ctrl-d (oder einfach nur 'd')

screen -r(esume)

Wurden mehrere Sitzungen detached praesentiert
  screen -r
eine Auswahl

screen -R -D (screen -RD)
  Reattach or create session


screen 
screen -r (reattach)

Wichtig: Nach Split in neue Region wechseln (C-a <TAB>) und dort neue Shell kreieren (C-a c) oder zuweisen (C-a 1)

Wichtigste Befehle
C-a gefolgt von
  : => Command-Line-Mode
    title Fenstertitel vergeben
  A Fenstertitel vergeben
  c (create new window and shell)
  Q (Nur aktuelles Fenster (jedoch alle Shells) behalten) z.B. um Split-Windows zu schliessen
  S (horizontaler Split)
  | (vertikaler Split)
  " Fensterliste
  <blank> naechste Sitzung/Shell
  n naechste Sitzung/Shell
  N zeige Nummer der Sitzung/Shell
  d detach
  0-9 Sitzung mit Nummer
  C-\ Alle Sitzungen und screen beenden
  ? Hilfebildschirm
  <TAB> naechste Region (bei Split)

Top

tmux

Unterscheidung
  Windows
  Panes (Unterteilungen ein und desselben Fensters)

Sessions
  tmux ls (list sessions)
  tmux kill-session -t myname
  Ctrl-b d detach
  tmux a(t(ach)) attach
  tmux new -s myname Neue Session "myname"
  tmux a -t myname (re)attach session "myname"

Panes
  Ctrl-b "                     Split horizontal
  Ctrl-b %                     Split vertikal
  Ctrl-b x                     Kill pane
  Ctrl-b <Pfeil>               Pane wechseln
                               auch schnelle Kombination von Pfeilen nach Ctrl-b moeglich
  Ctrl-b q                     Anzeige der Pane-Nummern
                               Folgeeingabe der Nummer waehrend Anzeige wechselt zu diesem Panel
  Ctrl-b o                     Pane-Wechsel
  Ctrl-b Ctrl-o                Pane-Rotation
  Ctrl-b z                     Toggle Pane-Fullscreen
  Ctrl-b Alt 1-5               Pane-Anordnung nach Voreinstellung 1-5
    Ctrl-b Alt 1               Nebeneinander mit GLEICHER Breite
    Ctrl-b Alt 2               Untereinander mit GLEICHER Hoehe
                               Cave: 5 == tiled
  Ctrl-b Ctrl <Pfeil>          Pane-Größe in 1er-Schritten ändern
  Ctrl-b Alt  <Pfeil>          Pane-Größe in 5er-Schritten ändern
  Ctrl-b {}                    Pane-Swap (previous|next)

Windows
  Ctrl-b c Neues Fenster
  Ctrl-b n Wechsel zu naechstem Fenster
  Ctrl-b p Wechsel zu vorherigem Fenster
  Ctrl-b 0-9 Wechsel zu Fenster 0-9
  Ctrl-b w Anzeige aller Fenster (analog Ctrl-A " bei screen)
  Ctrl-b & kill windows
  Ctrl-b , name window

Command-Mode
  Ctrl-b :                     Enter command-mode
         : split-window -h     untereinander
         : split-window -v     nebeneinander
         : resize-pane -L|R|D|U 20  20 Zellen in angegeben Richtung vergroessern/verkleinern

In .tmux.conf anlegen, um letzten Pfadbestandteil in Statusleiste anzuzeigen 
  set-option -g status-interval 15
    (Cave: status-interval ist das Update-Intervall in Sekunden)
  set-option -g automatic-rename on
  set-option -g automatic-rename-format '#{pane_current_path}'
    cf. man tmux
      b: => basename 
        set-option -g automatic-rename-format '#{b:pane_current_path}'
      d: => dirname 
        set-option -g automatic-rename-format '#{d:pane_current_path}'
  set -g display-panes-time 4000
    Millisekunden, ueber welche die Pane-Nummern mit
      Ctrl-b q
    angezeigt werden und einen Wechsel durch Folgeeingabe der
    Nummer erlauben

Top

sed

sed -i.bak -e '5,10d;12d' file    # Zeile 5 bis 10 und Zeile 12 loeschen; Backup-File anlegen
--------------------------------------------------------------------------------------------------------------------
Option -E ermoeglicht extended regular expressions, d.h. keine Escape-\ vor z.B. Klammern

sed -E '
  s/([0-9])\.([0-9])/\1\2/g             # Tausendertrenner entfernen
' Eingabe.csv > Ausgabe.csv
--------------------------------------------------------------------------------------------------------------------

sed -n /anfang/,+3{   # Cave: +3 und ~3 (naechstes Vielfaches von 3) erlaubt, -3 nicht
  p
}

sed '{
  /sed /{
          i\
  }
}' Howto.txt > out

--------------------------------------------------------------------------------------------------------------------

      sed -i -e '/verrechnet/!{                              # Nur Zeilen ohne "verrechnet"-Vermerk
                   /^'${dateOfBooking}';'${value}'/{         # Potentieller Match
                      x                                      # Tausch: Pattern-Space <-> Hold-Space
                      /verrechnet/{                          # War "verrechnet" in Hold-Space ?
                        x                                    # Pattern-Space wiederherstellen
                        b                                    # Keine weiteren Kommandos anwenden und Zeile ausgeben
                      }
                      /verrechnet/!{                         # Kein "verrechnet" in Hold-Space gewesen ?
                        x                                    # Pattern-Sapce wiederherstellen
                        s/^\('${reverseDateOfBooking}';'${value}'.*\)/\1 verrechnet/    # "verrechnet anhaengen"
                        h                                                               # Zeile mit Verrechnungsvermerk in Hold-Space kopieren
                      }
                   }
                 }' $commentFile

--------------------------------------------------------------------------------------------------------------------

    sed -i -n -e '1,/;"*'$paenultSaldo'"*$/ {   # Von erster Zeile bis Zeile mit Eintrag $paenultSaldo
                    /;"*'$paenultSaldo'"*$/d    # letzte Zeile loeschen
                    p                     # andere Zeilen ausgeben
                  }' $ultima

--------------------------------------------------------------------------------------------------------------------

sed -i -n -e '/^'${yearOfInterest}'/p' -e '/^Datum/p' "${resultFile}"

--------------------------------------------------------------------------------------------------------------------

    sed -i ${lineNum}'s/!'${table}'!/!'${table}${count}'!/' "${file}"

--------------------------------------------------------------------------------------------------------------------

  sed -n '
    /BEGIN:VEVENT/,/END:VEVENT/{
      /DTSTART/{
        s/DTSTART;VALUE=DATE://
        s/DTSTART://
        s/DTSTART;TZID=Europe\/Berlin://
        s/"//g
        s/\\//g
        h                     # Hold-Space
      }
      /DESCRIPTION/{
        s/DESCRIPTION:\(.*\)/(\1)/
        H                     # Netto-Beschreibung geklammert an Hold-Space anhaengen
      }
      /SUMMARY/{
        s/SUMMARY://
        s/"//g
        s/\\//g
        H                     # an Hold-Space anhaengen
        g                     # Hold-Space => Pattern-Space
        s/\(.*\)\n\((.*)\)\n\(.*\)/\1: \3 \2/ # Reihenfolge der durch Newline getrennten 3 Teile andern: Datum/Zeit\n(Kommentar)\nTitel => Datum/Zeit: Titel (Kommentar)
        s/()//                # Leere Kommentare loeschen
        p
      }
    }
  ' "$icsFile" > "$patternFile"

--------------------------------------------------------------------------------------------------------------------

      sed -i -e '/<d19/{ 
                   /<\/d19/!{ 
                     N 
                     s/\n/ /g 
                   } 
                 }' $rawXml
      checkReturn sed

--------------------------------------------------------------------------------------------------------------------

sed -i \
  's///g # alle von Griechisch-Lexer stets belassenen  entfernen
   s/ä/\ä/g 
   s/ö/\ö/g
   s/ü/\ü/g 
   s/Ä/\Ä/g 
   s/Ö/\Ö/g 
   s/Ü/\Ü/g 
   s/ß/\ß/g 
   s/(em\([[:alpha:]]\+\)[[:space:]]\+\([^)]\+\))/<em class="\1">\2<\/em>/g 
   s/(li[[:space:]]\+\([^)]\+\))/<li>\1<\/li>/g 
   s/(img[[:space:]]\+\([^)]\+\))/<img src="\1" width="10%" height="10%" alt=""\/>/g 
   s/(imgb[[:space:]]\+\([^)]\+\))/<img src="\1" width="10%" height="10%" alt="" border="1"\/>/g 
   s/

/<br\/><br\/>/g s/
/<br\/>/g' "$file" -------------------------------------------------------------------------------------------------------------------- sed -n '/Filter.*stream/,/^endstream/ { /Filter.*stream/d /^endstream/d p }' "$qualInFile" > "$qualOutFile" -------------------------------------------------------------------------------------------------------------------- sed -n -e '/<Placemark>/,/<\/Placemark>/{ # Innerhalb eines Placemark-Tags #------------------------------------------------ # Bei gefundenem Pfad Pfad-Marker setzen und # Anfang eines Placemark-Tags ausgeben #------------------------------------------------ /Path/{ # "Path" vorhanden ? s/.*/Pfad_gefunden/ # Pfad-Marker erzeugen h # Pfad-Marker => hold space #------------------------------------------------ # Anfang eines Placemark-Tags ausgeben #------------------------------------------------ i\ <Placemark>\ <name>$name</name>\ <styleUrl>#lineStyle</styleUrl>\ <Style>\ <LineStyle>\ <color>ff0000ff</color>\ <width>5</width>\ <scale>5</scale>\ </LineStyle>\ </Style>\ <LineString>\ <tessellate>1</tessellate>\ <coordinates> } #--------------------------------------------------- # Bei Ende eines Placemarks mit Pfad Pfad-Marker in hold space loeschen # und Placemark-Tag in der Ausgabe abschliessen #--------------------------------------------------- /<\/Placemark>/{ # Placemark-Ende g /Pfad_gefunden/{ # Pfad-Marker vorhanden ? s/.*// # Leerstring erzeugen h # => Pfad-Marker in hold space loeschen #------------------------------------------------ # Ende eines Placemark-Tags ausgeben #------------------------------------------------ i\ </coordinates>\ </LineString>\ </Placemark> } } #--------------------------------------------------- # Zahlentupel # 6.451126,51.664082,22.18 #--------------------------------------------------- /^[[:digit:]\., ]*$/{ # Falls Zahlentupel G # hold space mit Newline anhaengen /Pfad_gefunden/{ # Pfad-Marker vorhanden ? P # Zahlen (bis Newline) ausgeben } } }' "$infile" >> $outfile -------------------------------------------------------------------------------------------------------------------- sed -n -e '/EXTINF/{ #---------------------------------------------- # Angaben vor Sendernamen loeschen, # Leerzeichen aus letzterem entfernen, # Umlaute ersetzen, # Sendername gross schreiben #---------------------------------------------- s/#EXTINF:[,0-9 ]\+// s/ /_/g s/Ä/Ae/g s/Ö/Oe/g s/Ü/Ue/g s/ä/ae/g s/ö/oe/g s/ü/ue/g s/.*/\U&/ #---------------------------------------------- # Streaming-URL in naechster Zeile lesen #---------------------------------------------- N #---------------------------------------------- # Zeilen Verketten #---------------------------------------------- s/\n/:/ #---------------------------------------------- # Verkettetung ausgeben #---------------------------------------------- p }' "$file" -------------------------------------------------------------------------------------------------------------------- sed -n \ -e '/^\(leftstring\|rightstring\|label\|let\)/ { #------------------------------------------------------------------------------ # Ersetzung aller Zellenbezeichner mit 1-stelliger Zeile: # rightstring AC1 = "Hugo ist lieb" # => # rightstring 001AC = "Hugo ist lieb" #------------------------------------------------------------------------------ s/^[[:alpha:]]\+ \+\([[:alpha:]]\+\)\([[:digit:]]\{1\}\) /00\2\1 / #------------------------------------------------------------------------------ # Ersetzung aller Zellenbezeichner mit 2-stelliger Zeile: # let Q23 = 0.544*$B$7 # => # let 023Q = 0.544*$B$7 #------------------------------------------------------------------------------ s/^[[:alpha:]]\+ \+\([[:alpha:]]\+\)\([[:digit:]]\{2\}\) /0\2\1 / #------------------------------------------------------------------------------ # sc-Funktionen => ODF-Funktionen, bitte ergaenzen #------------------------------------------------------------------------------ s/@sum/summe/g #------------------------------------------------------------------------------ # Dezimalpunkt => Dezimalkomma #------------------------------------------------------------------------------ s/\([[:digit:]]\)\.\([[:digit:]]\)/\1,\2/g #------------------------------------------------------------------------------ # Einfuegen des "Internal Field Separators": " = " => "|" #------------------------------------------------------------------------------ s/ \+= \+/|/ #------------------------------------------------------------------------------ # Vor Rechenausdruecken, also nicht nur einer einzigen (!) Zahl, fuehrendes "=" # fuer ODF-Formeln einfuegen #------------------------------------------------------------------------------ # Falls kein String, also kein Textfeld, damit also Zahl oder Rechenausdruck #------------------------------------------------------------------------------ /["]/! { #---------------------------------------------------------------------------- # Falls rechts von "|" bis Zeilenende nicht nur eine einzige Zahl mit optionalem Dezimaltrenner #---------------------------------------------------------------------------- /|[[:digit:]]\+,\{0,1\}[[:digit:]]\+$/! { #-------------------------------------------------------------------------- # fuehrendes '=' fuer Formelerkennung in ODF einfuegen #-------------------------------------------------------------------------- s/|/|=/ } } p }' $infile | sort > $tmpfile -------------------------------------------------------------------------------------------------------------------- sed -e '/^-/d' \ -e '/ *\(Summe\|Datum\|Soll\)/d' \ "$account" | sort -b -t '|' -k 3 > "$out" -------------------------------------------------------------------------------------------------------------------- sed -i -n '/^\('${chapters//,/\\|}'\);/p' "$randomFile" -------------------------------------------------------------------------------------------------------------------- done < <(sed -n "$startLine,${endLine}p" "$infile") -------------------------------------------------------------------------------------------------------------------- sed '/^<synonym>/{ s/ᾰ́\|ā\|ά\|ᾱ\|ἄ\|ά\|ὰ\|α\|ἀ\|ἁ\|ἂ\|ἃ\|ἅ\|ἆ\|ἇ\|Α\|Ἀ\|Ἁ\|Ἂ\|Ἃ\|Ἄ\|Ἅ\|Ἆ\|Ἇ\|ᾲ\|ᾳ\|ᾴ\|ᾶ\|ᾷ\|Ὰ\|Ά\|ᾼ/a/g s/β\|Β/b/g s/γ\|Γ/g/g s/δ\|Δ/d/g s/έ\|ἔ\|έ\|ὲ\|ε\|ἐ\|ἑ\|ἒ\|ἓ\|ἕ\|Ε\|Ἐ\|Ἑ\|Ἒ\|Ἓ\|Ἔ\|Ἕ\|Ὲ\|Έ/e/g s/ζ\|Ζ/z/g s/h̃\|ή\|ἤ\|ἥ\|ή\|ὴ\|η\|ἠ\|ἡ\|ἢ\|ἣ\|ἥ\|ἦ\|ἧ\|Η\|Ἠ\|Ἡ\|Ἢ\|Ἣ\|Ἤ\|Ἥ\|Ἦ\|Ἧ\|ῂ\|ῃ\|ῄ\|ῆ\|ῇ\|Ὴ\|Ή\|ῌ/h/g s/θ\|Θ/q/g s/ΐ\|ῑ\|ĩ\|ί\|ί\|ὶ\|ι\|ἰ\|ἱ\|ἲ\|ἳ\|ἵ\|ἶ\|ἷ\|ἴ\|Ι\|Ἰ\|Ἱ\|Ἲ\|Ἳ\|Ἴ\|Ἵ\|Ἶ\|Ἷ\|ῖ\|Ὶ\|Ί/i/g s/κ\|Κ/k/g s/λ\|Λ/l/g s/μ\|Μ/m/g s/ν\|Ν/n/g s/ξ\|Ξ/c/g s/ό\|ὄ\|ό\|ὸ\|ο\|ὀ\|ὁ\|ὂ\|ὃ\|ὅ\|Ο\|Ὀ\|Ὁ\|Ὂ\|Ὃ\|Ὄ\|Ὅ\|Ὸ\|Ό/o/g s/π\|Π/p/g s/r\|ρ\|ῥ\|Ρ\|Ῥ/r/g s/σ\|ς\|Σ/s/g s/τ\|Τ/t/g s/ύ\|υ\|ὔ\|ύ\|ὺ\|ὐ\|ὑ\|ὒ\|ὓ\|ὕ\|ὖ\|ὗ\|Y\|Ὑ\|Ὓ\|Ὕ\|Ὗ\|ῦ\|Ὺ\|Ύ/u/g s/φ\|Φ/f/g s/χ\|Χ/x/g s/ψ\|Ψ/y/g s/w̃\|ώ\|ὤ\|ᾠ\|ώ\|ὼ\|ω\|ὠ\|ὡ\|ὢ\|ὣ\|ὥ\|ὦ\|ὧ\|Ω\|Ὠ\|Ὡ\|Ὢ\|Ὣ\|Ὤ\|Ὥ\|Ὦ\|Ὧ\|ῲ\|ῳ\|ῴ\|ῶ\|ῷ\|Ὼ\|Ώ\|ῼ/w/g s/>[^a-z]/>/ }' "$tmpFile" > "$outFile" -------------------------------------------------------------------------------------------------------------------- sed ' s/<img[^>]*>//g # nervige Images entfernen s/nowrap=""//g # stoerende Attribute entfernen s:</tr>:</tr>\n:g # Zeilenumbrueche nach Tabellenzeilen ' "$container" > "$containerTmp" -------------------------------------------------------------------------------------------------------------------- sed ' /Genehmigung steht aus/{ N # Naechste Zeile einlesen und s/\n// # Zeilenumbruch dazwischen loeschen } ' "$file" > "$tmp" -------------------------------------------------------------------------------------------------------------------- sed ' /placeholder_0/{ s//'"$time"'/ } /placeholder_1/{ r '$report' d # darf erst NACH read stehen } ' "$websiteTemplate" > "$website" -------------------------------------------------------------------------------------------------------------------- sed -n ' /<Beschreibung>/,/<\/Beschreibung>/{ /<Beschreibung>/d /<\/Beschreibung>/d s/^[[:space:]]*#// p } ' "$file" >> "$outfile" -------------------------------------------------------------------------------------------------------------------- sed ' /placeholder_0/{ r '$citation' d # darf erst NACH read stehen } /placeholder_1/{ s//'"$time"'/ } /placeholder_2/{ r '$websiteConfig' d # darf erst NACH read stehen } ' "$websiteTemplate" > "$website" -------------------------------------------------------------------------------------------------------------------- sed '/^[[:space:];]*$/{ d # Quasi-Leerzeilen loeschen } /AZDEPA/d # Vertragszeile loeschen /^[[:space:]]*Date/{ s/^/#/ # Header-Zeile kommentieren } s/[^[:space:]]\+greifend/uebergreifend/g # verungluecktes erstes Zeichen bei ..bergreifend korrigieren #---------------------------------------------------------------------------------------------- # Namenskorrekturen #---------------------------------------------------------------------------------------------- s/D.niel/Daniel/g /Kuelheim/{ s/Ren./Rene/ } /Fink/{ s/Marko/Marco/ } #---------------------------------------------------------------------------------------------- s/[[:space:]]\+€[[:space:]]\+//g # Euro-Zeichen mit Leerzeichen loeschen s/[[:space:]]\+;/;/g # Leerzeichen loeschen s/;[[:space:]]\+/;/g # Leerzeichen loeschen s/ä/ae/g s/ü/ue/g s/ö/oe/g s/Ä/Ae/g s/Ü/Ue/g s/Ö/Oe/g s/ß/ss/g s/[[:space:]]*Dr\.[[:space:]]*// # Akad. Titel loeschen ' "$infile" > "$infileTmp" -------------------------------------------------------------------------------------------------------------------- #------------------------------------------------------------------------------------------- # Nur Zeilen mit Datum oder "dispatched" beibehalten #------------------------------------------------------------------------------------------- sed -n '{ /\(^ *[0-9]\{4\}\|dispatched\)/{ # Nur Zeilen mit Datum zu Beginn oder "dispatched" beibehalten s/^ *// # Initialen Whitespace loeschen s/\([0-9]\{4\}\)[- ]\([0-9]\{2\}\)[- ][0-9]\{2\}/\1\2/ # 2023-01-04 oder 2023 01 04 => 202301 von Datum nur Jahr und Monat beibehalten (auch bei fehlerhaften Eintragen ohne Bindestrich) s/\./,/g # Dezimaltrenner bereinigen (Cave: lazy-Variante: nicht geprueft wird, ob Punkt zwischen 2 Zahlen steht) s/ \+PRO/ PRO/ # Einzelnes Blank vor Projektnummer verdoppeln (fuer spaetere Strichpunktersetzung) /\(pending\|disabled\)/Id # Status-Ausschluesse s/groeger/Groeger/I s/troeger/Troeger/I s/ARNO/Arno/ s/ \{2,\}/;/g # Blankfolgen >= 2 durch ; ersetzen (funktioniert wegen "greedy") p # Ausgabe } }' "$out1" > "$out2" sed -i -n ' $!{ # Fuer alle Zeilen bis auf die letzte h # Zwischenspeichern n # Folgezeile einlesen /dispatched/{ # "dispatched"-Zeile ? g # Holdspace => Patternspace s/$/;dispatched/ # "dispatched" mit ";" anhaengen p # Ausgabe } /dispatched/!{ # Nein, Datumszeile x # Patternspace <=> Holdspace s/$/;/ # ";" anfuegen p # Ausgabe g # Patternspace => Holdspace s/$/;/ # ";" anfuegen p } } ${ s/$/;/ # ";" anfuegen und p # ausgeben } ' "$out2"

Top

awk

awk [ -F separator -FS=regex ] [ -v var=value ... ] [ -f prog  ... ] 
awk  -F '\t' '{ ... }' files
awk -FS="[\t\n]" ...
awk '{ ... }' var=willi *.tex var=heinz *.tex                             # 2 Durchlaeufe mit verschiedenen Initialisierungen VOR Verarbeitung jeweiliger Eingabedatei, aber NACH BEGIN-Abschnitt 
awk '{ print $n }' n=4 Datei_1 n=2 Datei_2
...  -v var=heinz                                                         # Variable wird VOR BEGIN-Abschnitt initialisiert

Modell
======

pattern { action }
pattern                                                                   # Default-Aktion: print
{ action }                                                                # Aktion ohne Bedingung == fuer jede Zeile
BEGIN und END                                                             # Special patterns
str1="hugo";
str2="willi";
str=str1 str2                                                             # Es gibt keinen speziellen Konkatenierungsoperator
a=(var1>var2) ? x^3 : x^4
$0 ~ /\.[ch]$/
/\.[ch]$/                                                                 # synonym ($0 ist Default-String)
$4 !~ /\.+,\.+/
-------------------------------------------------------
BEGIN {IGNORECASE=1}                                                      # Cave: Gilt global, nicht nur fuer 1 Vergleich
string=ABC
($0 ~ /a/)                                                                # case-insensitive-match
-------------------------------------------------------
NF == 0                                                                   # Leerzeile
NF > 3                                                                    # Anzahl Felder
NR < 5                                                                    # Zeilennummer
if((col+0) > NF)                                                          # Cave: Zwangskonvertierung String => Zahl
(NR == 3) && (FILENAME ~ /[0-9][a-z]/)                                    
(NR == 2),(NR == 9)                                                       # Fuer Zeilen 2-9
$1 == "Hugo" { print $2; }
/Hugo/ || /Willi/ { ... }
! /Franz/ { ... }
/<hugo>/,/<\/hugo>/                                                       # Innerhalb Tag
$1 == "on",$1 == "off" { ... }
echo "Heinz Willi Franz" | awk '{ print $3 $2 $1}                         # Nicht-Komma-separierte Elemente werden in awk konkateniert => FranzWilliHeinz
echo "Heinz Willi Franz" | awk '{ print $3,$2,$1}                         # ',' bewirkt Einfuegen des Default OFS (' ') => Franz Willi Heinz
awk '{ OFS="..."; print $1, $2 }                                          # Output-Field-Separator
awk '{ sum += length($0) } END { print "Summe: " sum }'                   # Garantierte Default-Initialiserung jeder Variable macht sum=0 unnoetig
awk '{ print $1, log($1) }' 
awk -v column=5 '{ sum+=$column } END { print sum/NR }'
awk '{ sum+=$NF; print $NF, sum }                                         # laufende Summe der letzten Spalte
awk '/pattern|pattern/ { print FILENAME ": " NR " : " $0}' files          # egrep-Ersatz
awk 'BEGIN { FS=OFS="\t" } { print $3, $2 }' infile > outfile
awk 'BEGIN { ORS="\n\n" } { print }' files                                # Leerzeilen einfuegen
awk 'BEGIN { ORS =" "; RS="<[^<>]*>" } { print }' *.html                  # Fortgeschritten: HTML-Tags werden zu record-separators, in Ausgabe durch ' ' ersetzt und damit praktisch entfernt
for (key in assocArr){
  if(assocArr[name] == var){
    break
  }
}

#---------------------------------------------------
#!/usr/bin/awk -f                                                         # Shebang erfordert -f-Option

{
  print "Na also " $0; 
}
#---------------------------------------------------
PROCINFO["sorted_in"] = "@ind_str_asc";                                   # Sortierung
#---------------------------------------------------
delete array[key]
if !(key in assocArr) ...                                                 # richtig
if(assocArr[key] != "")                                                   # falsch, da hierbei assocArr[key] (leer) angelegt wird
if ((key1,key2,key3) in tripleAssocArr)                                   # Elementpruefung bei 3-dimensionalem Hash
#---------------------------------------------------
getline
=======
getline var < file
while((getline $words[nWords++] < file) > 0){
  ...
}
#---------------------------------------------------
# Zuweisung einer Feld-Variable (hier auf sich selbst)
# ersetzt FS durch OFS in aktuellem record
#---------------------------------------------------
awk 'BEGIN{OFS=":"} {$1=$1; print}' < file                                # a b c d => a:b:c:d  # print gibt record OFS-getrennt aus
#---------------------------------------------------
cmd | getline

  "date" | getline now                                                    # command wird in '"' eingeschlossen !
  close("date")

  command="head -n 15 /etc/hosts"
  while((command | getline line) > 0){
  }
  close(command)
#---------------------------------------------------
tmp=/tmpfile
command="sort -n > " tmp                                                  # Cave: Konkatenation 2er Strings
for (key in assocArr){
  print key ": " assocArr[key] | command
}
close(command)
#---------------------------------------------------
tmp=/tmpfile
for (key in assocArr){
  print "name: " assocArr[key] > tmp
}
close(tmp)
system("sort < " tmp)                                                     # Cave: String-Konkatenation, Cave: Jeder Aufruf von system(...) startet neue shell
#---------------------------------------------------
system("cat <<EOF\neins\nzwei\ndreiEOF")
#---------------------------------------------------
myfunc(arg1,arg2,   result){                                              # Lokale Variable result wird in Deklaration deklariert und (Konvention) durch Whitespace getrennt
  result =arg1 " " arg2
  return result
}
myfunc("Hugo","Willi")
#---------------------------------------------------
monthString="Jan Feb Maer Apr Mai Jun Jul Aug Sep Okt Nov Dez";
split(monthString,months);
printf(Monat: %s\n",months[5]);
#---------------------------------------------------
match("foobar",/(f+).*(b+)/,matchArr)
printf("Alles: %s\n",matchArr[0]);
printf("Erste Klammer: %s\n",matchArr[1]);
printf("Zweite Klammer: %s\n",matchArr[1]);
#---------------------------------------------------
Funktionen
==========
  passing convention:
    values are passed by value
    arrays are passed by reference
  myfunc(i,   j)                                                          # Konvention: lokale Variablen nach Argumenten durch White-Space getrennt (j ist lokal, aber uebergeben werden darf nur i)
  substr(string,start,len)
  toupper(string)
  tolower(string)
  index(string,pattern)
  match(string,regex)
    alternativ: string ~ regex
  sub(regex,replacement,string)
  gsub(regex,replacement,string)                                          # Default-string ist $0
    Cave: '&' in replacement fuegt match ein
      gsub([aeiou],"&&")                                                  # verdoppelt gefundene Vokale der aktuellen Zeile

  result=gensub(regex,replacement,howto,string)                           # Cave: Rueckgabe des Ergebnisses UND Faehigkeit zu back-references
    resource=gensub(/([[:alpha:]]+)[[:space:]]*,[[:space:]]*([[:alpha:]]+)/, "\\2_\\1", "g", resource);

  split(string,array,regex)                                               # Default-regex ist Wert von FS (field-separator) => Rueckgabe der Array-Laenge
  split(string,array,"")                                                  # Split jedes Zeichens
  split("",array)                                                         # Effizientes Loeschen von array
#---------------------------------------------------
# date and time
#---------------------------------------------------
now=systime();                                                            # number of seconds (epoch)
then=mktime("2023 12 31 23 00 00")
printf("%s <=> %s\n",strftime("%F",now),strftime("%F",then));             # %F analogous to 'date'-Format-String => "%Y-%m-%d"

year=2022;
month=06;
day1=13;
day2=27;
secsPerDay=3600.0*24.0;
startString=year " " month " " day1 " 03 00 00";
startTime=mktime(startString);
endString=year " " month " " day2 " 03 00 00";
endTime=mktime(endString);
days=sprintf("%d",((endTime-startTime)/secsPerDay)+1);

Top

mc

.config/mc/mc.ext

(Shift) F5                       # Copy
(Shift) F6                       # Move
F7                               # Verzeichnis anlegen
F8                               # Delete
F10                              # Beenden
F4                               # vim
F3                               # Viewer

 

Alt-,                            # Toggle Left/Right - Top/Bottom-Ansicht
Alt-t                            # Cycle Listing-Modes
Ctrl-t                           # Objekte selektieren/deselektieren
Ctrl-u                           # Panels tauschen
Ctrl-PgUp                        # Vaterverzeichnis
Alt-.                            # Toggle hidden files
Alt-i                            # Verzeichnis in Nachbar-Panel laden
Alt-o                            # Inhalt des Verzeichnisses in anderem Panel laden
Alt-H                            # Chronik
Alt-y                            # vorheriges Verzeichnis in Historie
Alt-u                            # naechstes Verzeichnis in Historie
Alt-?                            # Datei suchen analog 'find'
Alt-s <Anfangsbuchstaben>        # Springe zu Datei nach Muster ... (Wildcards * ?)
  mehrfach => naechster Treffer
Ctrl-\                           # Directory Hotlist (funktioniert nicht unter Windows (cygwin/wsl)
Ctrl-4                           # Directory Hotlist (funktioniert unter Windows)
Ctrl-o                           # Toggle shell
Ctrl-space                       # Verzeichnisgroesse ermitteln (Anzeige im Panel)
Ctrl-x (s|v|l)                   # Symbolische Links oder harten Link im anderen Verzeichnis anlegen
                                   -s: absoluter Pfad
                                   -v: relativer Pfad
Ctrl-x c                         # chmod-Dialog
Ctrl-x d                         # Verzeichnisse vergleichen
Ctrl-x o                         # chown-Dialog
Ctrl-x t                         # Markierte Datei => Kommandozeile
Ctrl-x q                         # Toggle Quick-View der aktuellen Datei in anderem Panel
(Alt|Ctrl)-Enter                 # Selektierte Datei => Shell
Shift-(Alt|Ctrl)-Enter           # Selektierte voll qualifizierte Datei => Shell
+                                # Dateien selektieren nach Muster
\                                # Dateien nach Muster deselektieren
*                                # Auswahl umkehren (nur Dateien)
cd .tgz *.tar.gz
SSH/SFTP
  F9 R
    SFTP
      Achtung: .ssh/config wird ignoriert
    Shell-Link
      .ssh/config funktioniert
  cd sftp://heinz@strato
  cd sh://heinz@strato
  Ruecksprung: cd

Command-Line
  z.B. cd ...
    ESC-Tab => autocompletion
      mehrfach => Auswahl

Top

rsync

cf. Abschnitte

INCLUDE/EXCLUDE PATTERN RULES
ANCHORING INCLUDE/EXCLUDE PATTERNS

in man-Page

Wenn Dateien nur aufgrund abweichender Groesse uebertragen werden sollen:

rsync -rzv(n) --size-only dir/* dir2/

Grundregeln
===========

Pfade sind alle rekursiv ab root qualifizierten Verzeichnisse

Pattern werden rekursiv ueber alle so qualifizierten Pfade ab root matched
  /source
  /source/afile
  /source/adir
  /source/adir/bdir
  /source/adir/bdir/cfile

Jeder Match wird von links nach rechts auf den gesamten aktuellen Pfad angewandt

include-Matches kompensieren exclude-Matches nur genau auf derselben Ebene
  == Verhalten von unison
  da auf jeder Ebene ueber Aus-/Einschluesse enschieden wird, kommen unterhalb eines
  Ausschluesses gelegene Einschluesse nicht mehr zum Zuge

  excludeFile
    */  => Ausschluss aller Verzeichnisse
  includeFile
    /subdir/hugo.java  => wird nicht mehr angewandt, da subdir bereits ausgeschlossen wurde

-a impliziert recursive traversal

Trailing '/' oder nicht hat nur bei Quellverzeichnis Bedeutung
  rsync -a /source /target[/]
    Uebertraegt source 
  rsync -a /source/ /target[/]
    Uebertraegt Inhalte von source

Root ist immer das vor dem letzten '/' beschnittene Quellverzeichnis 

  rsync -a /a/b/c/d/ ..........
    Root: /a/b/c/d
  rsync -a /a/b/c/d  ..........
    Root: /a/b/c

* matched alles, stoppt jedoch bei '/', d.h. '/' wird mit-matched, DANACH jedoch gestoppt
  =>

  excludeFile:
    *   => schliesst alles aus, d.h. alle Verzeichnisse (mit trailing '/') und alle Dateien

  includeFile:
    */   => schliesst alle Verzeichnisse ein

? matched genau ein Zeichen außer '/'

** matched alles inkl. '/'

dirname/*** matched wie zusammen
  dirname
  dirname/**


Muster mit fuehrendem '/' sind unterhalb Root verankert
Muster ohne fuehrenden '/' matchen ueberall
Muster mit '/' irgendwo (ausser am Ende) matchen den gesamten Pfad
  sub/foo => matched ueberall im Pfad
Muster mit trailing '/' matchen nur Verzeichnisse (am Ende des Pfades)
  */ => matched jeweiliges Endverzeichnis des Pfades und damit rekursiv jeden denkbaren Pfad ab root

  rsync -a /source/adir  /target

  excludeFile
    /adir   => matched nur /source/adir, nicht /source/bdir/cdir/adir
    bdir/cdir => matched  /source/adir/bdir/cdir

Top

unison

Generell
========
  Grundregel 1: Man muss aufpassen, sich mit ignore nicht ein Verzeichnis bereits auszuschliessen,
                auf dessen spezielle Elemente (Verzeichnisse oder Dateien gleichermassen) 
                danach eine ignorenot-Regel angewandt werden soll

  => nicht moeglich ist daher, in einem Verzeichnisbaum nur alle *.java-Dateien oder alle src-Verzeichnisse zu sichern

  Grundregel 2: Jedes Element wird auf ALLE Regeln zu matchen versucht, sofern ein vorheriges ignore dieses nicht
                ausgeschlossen hat =>
                Eine Anweisungsfolge
                  Path=.ssr
                  ignore=Name logs
                anstelle
                  ignore=Path .ssr/logs
                ist gefaehrlich, da die ignore-Anweisung auch auf ALLE anderen Pfad-Anweisungen angewandt wird

  Wenn ein qualifiertes Element mit ignore ausgeschlossen wurde, kann ignorenot nicht auf
  Unterelemente angewandt werden, d.h.
    ignorenot Path=.ssr 
  verwirft .ssr und es gibt gar keine Elemente .ssr/* mehr, auf welche ein folgendes ignorenot-Muster
    ignorenot Path=.ssr/*.content
  angewandt werden koennte


  Richtig folglich
    ignore=Path .ssr/*
    ignorenot=Path .ssr/hugo
    
    .ssr wird nicht ausgeschlossen => naechste Elemente fuer den Algorithmus sind nun alle .ssr/* =>
    .ssr/* werden ausgeschlossen, .ssr/hugo jedoch nicht

  Daher funktioniert auch
    Ignore=Regex .*\.class
      matched den gesamten Pfad bis zu einem Verzeichnis oder einer Datei mit Endunge .class
      und schliesst daher effektiv alle *.class-Dateien in allen Unterverzeichnissen aus
  wohingegen das vermeintliche Positiv-Beispiel
    Ignorenot=Regex .*\.java
  nur auf Verzeichnisse und Dateien ueberhaupt angewandt wird, welche nicht zuvor durch ein 
    Ignore=Path ...
  ausgeschlossen wurden
    es funktioniert also nicht
      Ignore=Path repository/*  => schliesst alles direkt unter repository (bereits) aus, z.B. repository/subdir
      IgnoreNot=Regex .*\.java  => wuerde nur fuer repository/*.java (aus der ignorierten Teilmenge) funktionieren, da 
                                   alle respository/<unterverzeichnis> bereits ignoriert sind, wodurch z.B.
                                     repository/subdir/hugo.java
                                   als Match auf .*/.java gar nicht mehr ausgewertet wird
      Synonym sind
        IgnoreNot=Name *.ext 
          Ignoriert jedes Unterverzeichnis oder jede Datei, welche auf .ext enden (Achtung globbing: '/' wird durch * nicht matched, . matched '.')
        Ignorenot=Regex .*/\.ext
          Matched gesamten Pfad bis zu einem Verzeichnis/einer Datei mit Endung .ext

  Es klappt zumindest angenaehert, d.h. bestmoeglich
    path=A
    #------------------------------------------------------------------------------------------------------------------------------------
    # Globbing: Datei oder effektiv letztes Verzeichnis beginnend mit oder ohne '.', beliebiger Zeichenfolge, '.' und beliebiger Endung ausschliessen
    #           
    # Cave: Annahme ist, dass es kein Verzeichnis, sondern nur Dateien mit einem '.' gibt
    #       Dateien ohne '.' werden leider ebenfalls gesichert, da der Ausschluss nur von Dateien (nicht Verzeichnissen) ohne '.' nicht moeglich ist
    #------------------------------------------------------------------------------------------------------------------------------------
    ignore=Name {,.}*.*         
    #------------------------------------------------------------------------------------------------------------------------------------
    # Globbing: Dito, jedoch mit Endung java
    #------------------------------------------------------------------------------------------------------------------------------------
    ignorenot=Name {,.}*.java

  Achtung
  =======
  Path, Name und PathBelow verwenden globbing
    * matched beliebige Zeichenfolge außer '/' und zu Beginn ein '.'
    ? matched genau ein Zeichen außer '/' und zu Begin ein '.'
    ausserdem:
      [abc] 
        Zeichen a oder b oder c
    und {xx,yy,zz} 
        Zeichenfolge xx oder yy oder zz
  Regex verwendert Posix-Extended-Regular-Expression, d.h. .* matched alle Zeichen INKL. '/' und . matched ein beliebiges Zeichen

Anweisungen
===========
  ignore (oder ignorenot)
  Cave: 
    ignore=Regex ...
      Posix-Extended-Regular-Expression
        muss den gesamten Pfad matchen
        \. 
          matched '.'
        .* 
          matched alles, also auch '/'
       Beispiel
         ignore=Regex .*\.class
           sichert alles in allen Unterverzeichnissen außer Verzeichnissen oder Dateien, welche auf .class enden, da .* auch '/' matched
    ignore=(Path|PathBelow) ...
      File-Globbing
        * und ?
        Cave: * matched NICHT '/'
      BelowPath matched auf Path, zusaetzlich jedoch auch auf alles Darunterliegende
    ignore=Name logs
      jeder Unterverzeichnisbaum, dessen letztes Verzeichnis logs ist, oder jede Datei namens logs irgendwo im Baum wird ignoriert

 Fuer den Ausschluss einer Dateiart ausser in einem bestimmten Unterverzeichnis
   ignore=Name *.ext
     Cave: Globbing
   ignorenot=Regex .*/sollverzeichnis/*\.ext
     Cave: Posix-Extended-Regular-Expression

Top

Win32OLE mit Ruby

Ruby-Snippets zu Win32OLE (WSH, Outlook, Excel, Word)


Windows-Scripting-Host
======================

  wsh.AppActivate(pid)
  wsh.SendKeys(key)
  wsh=WIN32OLE.new('WScript.Shell'); checkValue(wsh)
  wsh.run("cmd.exe /C start microsoft-edge:http://www.google.de");
  #---------------------------------------------------------------
  processArray=Array.new
  taskList=%x(tasklist)
  puts("----------------------")
  taskList.split(/\n/).each { |task|
    # if(task.match(/^#{processName}\S+\s+(\d+)/i))
    if(task.match(/^#{processName}\s+(\d+)/i))
      puts("Job: #{$1}")
      processArray << $1
    end
  }

Win32OLE
========

  Outlook
  =======
    #---------------------------------------------------------------
    $outlook=WIN32OLE.new('Outlook.Application'); checkValue($outlook)
    $outlook=WIN32OLE.connect('Outlook.Application') 
    WIN32OLE.const_load($outlook,OutlookConst)
    $namespaceOutlook=$outlook.GetNamespace("MAPI")
    $topFolder=$namespaceOutlook.Folders.Item('heinz.breinlinger@allianz.de')
    sender.gsub!(/dr\.\s*/i,"")  # Akademischen Grad loeschen
    planviewFolder=$topFolder.Folders.Item($planviewFolderName)
    archiveFolder=planviewFolder.Folders.Item($archiveFolderName)
    archiveFolder.Items.each{ |mail|
      subject=mail.Subject
      (! subject.match(/#{$keyWord}/)) && die("outlook2Config: Betreff #{subject} enthaelt Begriff #{$keyWord} nicht")
      sender=mail.SenderName
      ...
    maskArr=subject.scan(/[0-9]{4}/)
    #---------------------------------------------------------------
    calendar.Items.each{ |appointment|
      i+=1
      if(appointment.entryID == entryID)
        return appointment
      end
    }
    #---------------------------------------------------------------
    mail=sourceFolder.Items.GetFirst
    mail.Move(targetFolder)
    #---------------------------------------------------------------
    while(planviewFolder.Items.Count != 0) do
      mail=planviewFolder.Items.GetFirst
      printf("Verschiebe %s in Ordner %s\n",mail.SenderName,$doneFolderName)
      mail.Move(doneFolder)
    end

  IE/Edge
  =========
    $ie=WIN32OLE.new('InternetExplorer.Application'); checkValue($ie)
    $ie.visible=true

  Excel
  =====
    #--------------------------------------------------------------------------------------------
    # ';' in Text ersetzen, da csv-Trennzeichen
    #--------------------------------------------------------------------------------------------
    puts("Replacing ; in sheet #{sheetName} ...")
    sheet.range("A1:ZZ1000").Replace({
                                       "What" => ";",
                                       "Replacement" => ","
                                     })
    #--------------------------------------------------------------------------------------------
    # Zeilenumbrueche ersetzen
    #--------------------------------------------------------------------------------------------
    puts("Replacing ; in sheet #{sheetName} ...")
    sheet.range("A1:ZZ1000").Replace({
                                       "What" => "\n",
                                       "Replacement" => " "
                                     })

    book.saveAs(file,ExcelConst::XlWorkbookDefault)
    #---------------------------------------------------------------
    sheet.Range("A1:C10").Clear
    sheet.Range("A1:C10").ClearContents
    book.worksheets(sheetNum).Cells.ClearContents
    #---------------------------------------------------------------
    book=$excel.Workbooks.add
    sheet=book.Worksheets.add
    #---------------------------------------------------------------
    percFormat="0,00%"
    currFormat="#.##0,00 \"Eur\";[Rot]-#.##0,00 \"Eur\""
    floatFormat="#.##0,00;[Rot]-#.##0,00"
    intFormat="#.##0;[Rot]-#.##0"
    dateFormat="TT.MM.JJ"
    timeFormat="hh:mm:ss"
    sheet.cells(row,col).numberFormat=currFormat
    sheet.range("A2:F60").numberFormat=currFormat
    sheet.range("A"+row.to_s+":F"+row.to_s).horizontalAlignment=ExcelConst::XlCenter (..XlLeft ..XlRight)
    #---------------------------------------------------------------
    # Konvertierung
    #---------------------------------------------------------------
    book=$excel.Workbooks.Open(qualFile); checkValue(book)
    book.saveAs(qualNewFile,ExcelConst::XlOpenXMLWorkbook)
    book.close
    #---------------------------------------------------------------
    $excel=WIN32OLE.connect('Excel.Application') 
    $excel=WIN32OLE.new('Excel.Application'); checkValue($excel)
    $excel.DisplayAlerts=false                  # verhindert Schlussfrage, ob gespeichert werden soll
    WIN32OLE.const_load($excel,ExcelConst)
    #---------------------------------------------------------------
    book=$excel.Workbooks.Open(file); checkValue(book)
    (1..book.worksheets.count).each{ |i|
      sheetName=book.worksheets(i).Name
      if(sheetName.match(/^#{name}/i))
        ...
    #---------------------------------------------------------------
    book=$excel.Workbooks.Open(file); checkValue(book)
    book.worksheets(sheetNum).Activate 
    sheetName=book.worksheets(sheetNum).Name
    book.saveAs(csvFile,ExcelConst::XlCSV) # alternativ: ExcelConst::XlCSVWindows|XlCSVMSDOS
    book.close
    #---------------------------------------------------------------
    numSheets=book.worksheets.count
    #---------------------------------------------------------------
    # Zellformat-Wandlung
    #
    # "a4" => 4,1
    #------------------------------------------------------------
    (! cell.match(/^[[:alnum:]]+$/)) && die("excelExtractFromFile: Falsches Zellenformat 1: #{cell}")
    (! cell.match(/^([[:alpha:]]+)([[:digit:]]+)$/)) && die("excelExtractFromFile: Falsches Zellenformat 2: #{cell}")
    column=$1.upcase # "A"
    row=$2           # "4"
    (! $excelColumnMapReverse.key?(column)) && die("excelExtractFromFile: Spalte #{column} ist nicht in Mapping-Tabelle enthalten")
    column=$excelColumnMapReverse[column]
    row=row.to_i
    column=column.to_i
    text=book.worksheets(sheetNum).cells(row,column).Value.to_s # String-Wandlung
    text=sheetNum.to_s+":"+cell.to_s+":"+text.encode!("ISO-8859-1")
    #------------------------------------------------------------
    book.worksheets(sheetNum).cells(row,column).Value=text
    #------------------------------------------------------------
    $excel.quit()
    #------------------------------------------------------------
    result=%x(tasklist /FI "IMAGENAME eq #{process}" /FI "PID ne #{$$}")
    #------------------------------------------------------------
    delete && sheet.Hyperlinks.Delete()
    colChar=$excelColumnMap[col]
    sheet.Hyperlinks.Add(sheet.Range(colChar+row.to_s),demandUrl,"",mouseOver,displayText)
    sheet.Range(colChar+row.to_s).NumberFormat="@"
    sheet.Range("A"+i.to_s+":Z"+i.to_s).Font.Size=8
    sheet.Range("C"+i.to_s+":C"+i.to_s).NumberFormat="#,## \" %\"" 
    sheet.cells(row,col).Value=cellContent.to_s
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    sheet.Columns("A:Z").Autofit
    $excel.activeWindow.DisplayZeros=0
    book.SaveAs(fileName+".xlsx") 
    book.ExportAsFixedFormat(ExcelConst::XlTypePDF,fileName+".pdf",nil,true)  # true ist "IgnorePrintAreas"
    book.Close
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    sheet=book.worksheets(1); checkValue(sheet)
    #------------------------------------------------------------------------------------------------------------------------------------------------
    book=$excel.Workbooks.Add; checkValue(book)
    sheet=book.Worksheets.Add; checkValue(sheet)
    sheet.Name="Anthologie"
    sheet.Tab.Color=rgb(61,163,95)
    sheet.Range("C2:D10000").NumberFormat="##.# \" Eur\"" 
    sheet.Range("A"+row.to_s+":D"+row.to_s).Interior.ColorIndex=40
    sheet.Range(3,8).Font.ColorIndex=6 # gelb
    sheet.Range("A1:J2").Font.Bold=1
    sheet.Range("A1:A10000").Autofilter(1,["Nova","Team"],ExcelConst::XlFilterValues) 
    sheet.Columns("A:Z").Autofit
    $excel.activeWindow.DisplayZeros=0
    #---------------------------------------------
    # Standardtabellenblaetter loeschen
    #---------------------------------------------
    1.upto(1){ |i|
      sheet=book.Worksheets("Tabelle"+i.to_s)
      sheet=book.worksheets("Referat"); checkValue(sheet)
      if(sheet)
        sheet.Delete
      end
    }
    book.Worksheets(1).Activate
    #---------------------------------------------
    comment=sheet.Range("I1:I1").AddComment
    comment.Text("Fuer erweitere Ansicht in Spalte A \"Resource\" anhaken")
    comment.Shape.TextFrame.AutoSize=true
    comment.Visible=true
    range=sheet.Range(sonstIstColChar+row.to_s)
    range.Comment && range.Comment.Delete
    #---------------------------------------------
    def makeComment(cell,comment)
      shape=cell.AddComment(comment).Shape
      shape.Width=400
      shape.Height=100
    end
    #---------------------------------------------
    sheet.Range("A1:J1").Font.Bold=1
    sheet.Range("A2:H2").Interior.ColorIndex=50
    sheet.Range("A3:H3").Interior.ColorIndex=44
    sheet.Range("C2").NumberFormat="# \" Tage\"" 
    sheet.Range("C3:D1000").NumberFormat="##.# \" Eur\"" 
    sheet.Range("E1:E1000").NumberFormat="#,## \" %\"" 
    sheet.Range("F3:F1000").NumberFormat="[Rot]##.# \" Eur\";[Farbe10]-##.# \" Eur\"" 
    sheet.Range("G3:G1000").NumberFormat="##.# \" Eur\"" 
    sheet.Range("H3:H1000").NumberFormat="[Rot]##.# \" Eur\";[Farbe10]-##.# \" Eur\"" 
    sheet.Range("A1:A1000").Autofilter(1,["Zeit","Projekt","Team"],ExcelConst::XlFilterValues) 
    sheet.Range("A"+row.to_s+":M"+row.to_s).Font.Bold=1
    sheet.Range("A"+row.to_s+":M"+row.to_s).Borders(ExcelConst::XlEdgeBottom).LineStyle=ExcelConst::XlContinuous
    sheet.Range("A"+row.to_s+":M"+row.to_s).Borders(ExcelConst::XlEdgeBottom).weight=ExcelConst::XlThin
    sheet.Range("A"+row.to_s+":M"+row.to_s).Borders(ExcelConst::XlEdgeBottom).weight=ExcelConst::XlMedium
    sheet.Range("A"+row.to_s+":M"+row.to_s).Borders(ExcelConst::XlEdgeBottom).ColorIndex=ExcelConst::XlAutomatic
    sheet.Columns("A:Z").Autofit
    $excel.activeWindow.SplitColumn=0
    $excel.activeWindow.SplitRow=3
    $excel.activeWindow.freezepanes=1 # Cave: Excel muss maximiert geoeffnet sein
    $excel.activeWindow.DisplayZeros=0
    sheet.Range("A1:M1").Autofilter
    sheet.Columns("A:M").AutoFit
    sheet.Columns("C:L").NumberFormat="0,0"
    sheet.Range("A2").Select
    $excel.activeWindow.freezepanes=1
    $excel.activeWindow.DisplayZeros=0
    book.SaveAs(Dir.getwd+"/Synopse.xls")
    book.Close
    #---------------------------------------------
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    # Rest-Formatierungen
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    sheet.Range("A1:J1").Font.Bold=1
    sheet.Range("A2:H2").Interior.ColorIndex=50
    sheet.Range("A3:H3").Interior.ColorIndex=44
    sheet.Range("C2").NumberFormat="# \" Tage\"" 
    sheet.Range("E1:E1000").NumberFormat="#,## \" %\"" 
    sheet.Range("F3:F1000").NumberFormat="[Rot]##.# \" Eur\";[Farbe10]-##.# \" Eur\"" 
    sheet.Range("G3:G1000").NumberFormat="##.# \" Eur\"" 
    sheet.Range("H3:H1000").NumberFormat="[Rot]##.# \" Eur\";[Farbe10]-##.# \" Eur\"" 
    #-----------------------------------------------------------------
    sheet.Range("A2").Select
    $excel.ActiveWindow.FreezePanes=true
    sheet.Columns("A:AZ").Autofit
    sheet.Range("A2:AZ1000").Sort({"Key1" => sheet.Range("B2:B1000")})
    #-----------------------------------------------------------------
    sheet.Range("A1:Z1").Autofilter
    sheet.Columns("A:Z").Autofit
    sheet.Range("A1:Z1").Font.Bold=1
    $excel.ActiveWindow.SplitColumn=0
    $excel.ActiveWindow.SplitRow=1
    $excel.ActiveWindow.FreezePanes=1
    #- - - - - - - - - - - - - - - - - - - - - - -
    # Blatt ans Ende stellen
    #   'nil' ist der 'before'-Parameter von sheet.Move
    #   der zweite Parameter ist 'after'
    #- - - - - - - - - - - - - - - - - - - - - - -
    sheet.Move(nil,book.Worksheets(2)) # Sheet "Linie" ist Nummer 2, da "Team" davor als Nummer 1 gesetzt wurde
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    # Querformat fuer PDF-Export
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    if($pdfExport)
      sheet.PageSetup.Orientation=ExcelConst::XlLandscape 
      sheet.PageSetup.PrintArea="A1:H#{PRINTAREAROW}"
    end
    #- - - - - - - - - - - - - - - - - - - - - - -
    # Standardtabellenblaetter loeschen
    #- - - - - - - - - - - - - - - - - - - - - - -
    1.upto(1){ |i|
      sheet=book.Worksheets("Tabelle"+i.to_s)
      if(sheet)
        sheet.Delete
      end
    }
    #- - - - - - - - - - - - - - - - - - - - - - -
    # Sheet "Linie" aktivieren
    #- - - - - - - - - - - - - - - - - - - - - - -
    book.Worksheets(1).Activate
    #- - - - - - - - - - - - - - - - - - - - - - -
    book.SaveAs($cwd+"\\"+scope+"_"+$projName+".xlsx") 
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    # PDF-Export der Datei, d.h. beider Sheets
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    if($pdfExport)
      book.ExportAsFixedFormat(ExcelConst::XlTypePDF,$cwd+"\\"+scope+"_"+$projName+".pdf",nil,true)  # true ist "IgnorePrintAreas"
    end
    #-----------------------------------------------------------------
    rangeVist=sheet.Range(vistColChar+row.to_s)
    #-----------------------------------------------------------------
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    # Cave: Hier muss die Blockform von "sub!" verwendet werden, da
    # die Backreference $1 erst NACH Abschluss des Patternmatch gesetzt wird.
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    budget2=(tage*tagessatz).to_s
      .sub!(/\./,",")               # "." durch "," ersetzen
      .sub!(/,(\d)$/) do            # Bei einer Nachkommastelle "0" anhaengen
        ",#{$1}0"
      end
      .sub!(/(\d)(\d{3},)/) do      # Tausendertrennzeichen "." setzen
        "#{$1}.#{$2}"
      end

  Word
  ====
    #---------------------------------------------------------------
    doc=$word.Documents.Open(qualFile); checkValue(doc)
    doc.saveAs2(qualNewFile,WordConst::WdFormatDocumentDefault)
    doc.close
    $word.quit()
    #---------------------------------------------------------------
    $word=WIN32OLE.connect('Word.Application'); checkValue($word)
    $word=WIN32OLE.new('Word.Application'); checkValue($word); checkValue($word)
    $word.Visible=1
    $word.DisplayAlerts=false # verhindert Schlussfrage, ob gespeichert werden soll
    WIN32OLE.const_load($word,WordConst)
    #------------------------------------------------------------
    if(replaceAll)
      modifier=WordConst::WdReplaceAll
      kind="alle Vorkommen"
    else
      modifier=WordConst::WdReplaceOne
      kind="erstes Vorkommen"
    end
    content=doc.Content
    find=content.find
    #------------------------------------------------------------
    doc=$word.Documents.Open(cwd+"/"+file); checkValue(doc)
    text=doc.Range.Text
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    # cf. https://docs.microsoft.com/en-us/office/vba/api/word.find.execute
    # cf. in Word (Ctrl-h) die korrespondierenden Suchen- und Ersetzen-Parameter
    #
    # 1. FindText
    # 2. MatchCase true
    # 3. MatchWholeWord true
    # 4. MatchWildCards false
    # 5. MatchSoundsLike false
    # 6. MatchAllWordForms false
    # 7. Forward true
    # 8. Wrap (am Dokumentende fortfahren)
    # 9. Format false (Formatierung ist kein Kriterium)
    # 10. ReplaceWith (Ersetzungs-String)
    # 11. Replace wdReplaceAll (wdReplaceOne, wdReplaceNone)
    # 12-15 vermutlich 4 aus: MatchPrefix, MatchSuffix, MatchPhrase, IgnoreSpace, IgnorePunct (nicht MatchKashida, MatchDicritics,
    #       MatchAlefHamza, MatchControl)
    #
    #             1       2    3    4     5      6    7    8                         9     10      11                      12-15
    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    find.execute(toReplace,true,true,false,false,false,true,WordConst::WdFindContinue,false,replacement,modifier,false,false,false,false)
    if(find.found)
      ...
    doc.saveAs2($confDir+"\\"+$lbHash[VERTRAG]+"_Leistungsbeschreibung.docx")

    #-----------------------------------------------------------------------------
    # Checkboxen loeschen
    #-----------------------------------------------------------------------------
    doc.FormFields.each{ |field|
      if(field.Type == WordConst::WdFieldFormCheckBox) 
        puts("Erasing checkbox #{i+=1} ...")
        field.CheckBox.value=false
      end
    }
    #-----------------------------------------------------------------------------
    # Checkboxen setzen
    #-----------------------------------------------------------------------------
    checkBoxes=$contractHash["checkboxes"];
    checkBoxes.split(',').each{ |name|
      puts("Setting checkbox #{name} ...")
      doc.FormFields(name).CheckBox.value=true;        # Word wirft Fehler, wenn kein Form-Element dieses Namens vorhanden => keine Pruefung noetig
    }
    #-----------------------------------------------------------------------------
    # Textersetzungen
    #-----------------------------------------------------------------------------
    wordReplace(doc,"<Hugo>","Willi") 
    #-----------------------------------------------------------------------------
    # Textformularfeld loeschen/setzen
    #-----------------------------------------------------------------------------
    # doc.FormFields("datum").TextInput.Clear
    # doc.FormFields("datum").Result="01.01.2024"
    #-----------------------------------------------------------------------------
    # Kalkulationstabelle einsetzen
    #-----------------------------------------------------------------------------
    # doc.ActiveWindow.Selection.InsertFile("C:\\Work_Config\\Budget\\Vertraege\\adesso\\Vertrag\\service-description.docx")
    #-----------------------------------------------------------------------------
    # Bild an Cursor-Position (Selection) einfuegen
    #-----------------------------------------------------------------------------
    # doc.ActiveWindow.Selection.InlineShapes.AddPicture("C:\\Work_Config\\Budget\\Vertraege\\adesso\\Vertrag\\calculation.png",false,true)
    #-----------------------------------------------------------------------------
    # Bild nach n. Buchstaben/Paragraphen einfuegen
    #-----------------------------------------------------------------------------
    # doc.Range(200).InlineShapes.AddPicture("C:\\Work_Config\\Budget\\Vertraege\\adesso\\Vertrag\\calculation.png",false,true)
    # doc.Paragraphs(5).Range.InlineShapes.AddPicture("C:\\Work_Config\\Budget\\Vertraege\\adesso\\Vertrag\\calculation.png",false,true)
    #-----------------------------------------------------------------------------
    # Bild in (einzig) vorhandenes Inhaltssteuerelement (aus Entwicklertools) 
    # des Typs Bild einfuegen, d.h. das vorhandene Bild aendern
    #-----------------------------------------------------------------------------
    doc.ContentControls.each{ |contentControl|
      if(contentControl.Type == WordConst::WdContentControlPicture) 
        puts("Found Picture-Control");
        contentControl.Range.InlineShapes.AddPicture("C:\\Work_Config\\Budget\\Vertraege\\adesso\\Vertrag\\calculation.png",false,true)
      end
    }
    #-----------------------------------------------------------------------------
    # Anzahl der Zeichen einer Auswahl ausgeben (=> Ermittlung des Zeichenindex ab Anfang moeglich)
    #-----------------------------------------------------------------------------
    # puts("Zeichenzahl: #{doc.ActiveWindow.Selection.Characters.Count}")
    #-----------------------------------------------------------------------------
    # Bookmark loeschen
    #-----------------------------------------------------------------------------
    doc.Bookmarks.each{ |bookmark|
      if(bookmark.Name == "definitions")
        puts("Bookmark-Start: #{bookmark.Start}");
        puts("Bookmark-End: #{bookmark.End}");
        bookmark.Select
        doc.ActiveWindow.Selection.Delete
      end
    }

Top

top

top
===

R: Sortierreihenfolge umkehren
P: Nach CPU sortieren
M: nach Speicher sortieren
<>: Sortierspalte wechseln
j: Prozessnamen => rechts
blank: Update der Liste (unabhaengig vom eingestellten Intervall)

Toggle
  1: Anzeige je CPU/Core
  l: Last (1. Zeile)
       1 == Auslastung bei 1 CPUs (Anzahl wartender Prozesse)
       4 == Auslastung bei 4 CPUs
  t: CPU/Task
       Prozentual mit/ohne Balken
  m: Memory (Prozent und xByte, je nach Option E)
     E: KByte => Petabyte
  B: Bold overall an/aus
  b: Bold Sortierspalte/relevante Zeile vs. Blocksatz Sortierspalte/Zeile
  x: Toggle sort field
  V: Forst-View
     v: mit Unterprozessen
  c: Prozesse mit Pfadangabe
  S: Zeitangabe

L Text: Prozessnamen "Text" finden (Cave: Keine '"')
  &: naechsten Treffer finden
  L <Return> Modus verlassen

f/F: Filterliste festlegen
     s: Eintrag => Sortierkriterium
     d/blank: Auswahl
     <Rechtspfeil> <auf/ab>: Nach oben oder unten verschieben <Enter>
u "user": Nur Prozesse des Nutzers

A: 4-Fensteransicht
k: Signal an Prozess


Impressum und Datenschutzerklärung