Dies ist eine alte Version des Dokuments!
Inhaltsverzeichnis
bash (Bourne SHell / Bourne-Again SHell)
In jedem Unix-Ähnlichen System findet sich die klassische Bourne SHell unter /bin/sh.
Aus diesem Grund scripte ich mit Vorliebe für diese Shell. Dann laufen die Scripte nicht nur auf Linux, sondern auch auf NetBSD, FreeBSD, Solaris, AIX und anderen Unix-Ähnlichen Betriebssystemen.
farbige Textausgabe (24bit Farben)
ESC[38;2;⟨r⟩;⟨g⟩;⟨b⟩m # RGB foreground color ESC[48;2;⟨r⟩;⟨g⟩;⟨b⟩m # RGB background color ESC[0m # reset
ESC: Darstellung mit\033- 1. Paramter:
38(Vordergrundfarbe) und48(Hintergrundfarbe) - 2. Paramter:
2(RGB Format verwenden) - 3/4/5. Paramter: rot/grün/blau Werte mit jeweils 8-bit in dezimal (0 - 255), weil
24 / 3 = 8-bit
Beispiel um Syntax zu vereinfachen
Variablen:
- TEXT: Text der printf übergeben wird
- XY
- X: Vordergrund (F) oder Hintergrund (B)
- Y: rot (R), grün (G) oder blau (B)
Umgebungsvariable als Shortcut
PRINT_COLOR='eval printf "\033[39m\033[49m"$(test ${#FG_RGB[@]} -eq 3 && printf "\033[38;2;${FG_RGB[0]};${FG_RGB[1]};${FG_RGB[2]}m")""$(test ${#BG_RGB[@]} -eq 3 && printf "\033[48;2;${BG_RGB[0]};${BG_RGB[1]};${BG_RGB[2]}m")"${TEXT}\033[0m"; unset TEXT FG_RGB BG_RGB;'
Nutzung
TEXT="Hello," FG_RGB=(255 255 255) BG_RGB=(0 0 0); $PRINT_COLOR && TEXT=" "; $PRINT_COLOR && TEXT="World!" FG_RGB=(0 0 0) BG_RGB=(255 255 255); $PRINT_COLOR && echo TEXT="Hello World!" FG_RGB=(0 0 0) BG_RGB=(255 255 255); $PRINT_COLOR && echo TEXT="Hello World!" FG_RGB=(127 0 255); $PRINT_COLOR && echo TEXT="Hello World!" BG_RGB=(127 0 255); $PRINT_COLOR && echo TEXT="Hello World!"; $PRINT_COLOR && echo
Achtung: Die Semikolon (;) sind wichtig!
Bash - Pattern
Klammererweiterung
Dann gibt es die Klammererweiterung (Brace-Expansion). Klammererweiterung passt technisch nicht in die Kategorie der Muster, ist aber ähnlich. Globs werden nur auf tatsächliche Dateinamen erweitert, aber Klammererweiterungen werden auf jede mögliche Permutation ihres Inhalts erweitert. So funktionieren sie:
$ echo th{e,a}n
then than
$ echo {/home/*,/root}/.*profile
/home/axxo/.bash_profile /home/lhunath/.profile /root/.bash_profile /root/.profile
$ echo {1..9}
1 2 3 4 5 6 7 8 9
$ echo {0,1}{0..9}
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19
Die Klammererweiterung wird durch eine Liste von Wörtern ersetzt, genau wie ein Glob. Diese Wörter sind jedoch nicht unbedingt Dateinamen, und sie sind nicht sortiert (als wären sie vorher gekommen).
Die Klammererweiterung erfolgt vor der Dateinamenerweiterung. Im zweiten echo-Befehl oben haben wir eine Kombination aus Klammererweiterung und Globs verwendet. Die Klammererweiterung geht zuerst und wir erhalten:
$ echo /home/*/.*profile /root/.*profile
Nach der Klammererweiterung werden die Globs erweitert und wir erhalten als Endergebnis die Dateinamen.
Klammererweiterungen können nur verwendet werden, um Wortlisten zu generieren. Sie können nicht für den Mustervergleich verwendet werden.
Es gibt einige interessante und nicht sehr intuitive Unterschiede zwischen den Bereichen in Zeichenklassen wie [a-z] und Klammererweiterung. Zum Beispiel erlaubt die Klammererweiterung das Rückwärtszählen, wie man bei {5..1} oder sogar {b..Y} sehen kann, während [5-1] nicht durch die Shell erweitert wird. [b-Y] kann je nach Gebietsschema erweitert werden oder nicht. Außerdem ignorieren Zeichenbereiche in Klammererweiterungen Gebietsschemavariablen wie LANG und LC_COLLATE und verwenden immer die ASCII-Reihenfolge. Globbing hingegen wird durch die Spracheinstellungen beeinflusst. Das folgende Fragment ist ein Beispiel für das Herunterzählen und die Anzeige von Zeichen in der Reihenfolge ihrer ASCII-Codes:
$ echo {b..Y}
b a ` _ ^ ] [ Z Y
Feldtrennzeichen - Delimiter (IFS)
Remote Procedure Call - RPC
- RPC mit BASH - Let's say you have a Bash shell script, and you need to run a series of operations on another system (such as via ssh).
- rpcsh - So, to solve this, you can use a technique called rpcsh – rpc in shell script…
automatische Ersetzung im Dateinamen
Hier wird die Dateiendung ".text" in ".txt" getauscht:
for Datei in *.mts; do mv -v "${Datei}" ${Datei%.text}.txt; done
ffmpeg -i 00001.text 00001.txt
Optionen
> man bash Laut Doku werden bei "$*" die Elemente durch $IFS (meisten der Zeilenumbruch) getrennt behandelt. Laut Doku werden bei "$@" die Elemente durch Leerzeichen getrennt behandelt. In meinen Test konnte ich bei beiden nur einer Erweiterung mit Leerzeichen erkennen.
Ich konnte keinen Unterschied zwischen "$*" und "$@" feststellen.
- /tmp/test.sh
#!/bin/bash echo '# 1: "$*"' echo "$*" echo '# 2: $*' echo $* echo '# 3: "$@"' echo "$@" echo '# 4: $@' echo $@ echo '# 5: "$#"' echo "$#" echo '# 6: $#' echo $# echo '# 7: #' echo "$1" echo "$2" echo "$3" echo "$4" echo "$5" echo "#------------------------------------------------------------------------------#" echo $1 echo $2 echo $3 echo $4 echo $5
> /tmp/test.sh 1 2 3 4 "5 6 7 8" # 1: "$*" 1 2 3 4 5 6 7 8 # 2: $* 1 2 3 4 5 6 7 8 # 3: "$@" 1 2 3 4 5 6 7 8 # 4: $@ 1 2 3 4 5 6 7 8 # 5: "$#" 5 # 6: $# 5 # 7: # 1 2 3 4 5 6 7 8 #------------------------------------------------------------------------------# 1 2 3 4 5 6 7 8
Funktionen
In der Bash wird eine Funktion fast so gebaut wie in "C".
Alle Variablen, die außerhalb der Funktion definiert wurden, sind auch in der Funktion verwendbar:
#!/usr/bin/env bash
VARIABLE="01"
funktionx()
{
echo "VARIABLE=${VARIABLE}"
}
funktionx
Wird eine Skript-Datei mit z.B. zwei Parametern aufgerufen, dann sind bekanntlich diese vier übergebenen Parameter in der Datei als "$1" und "$2" verwendbar.
Genauso verhält es sich mit den Parametern bei den Funktionen:
#!/usr/bin/env bash
NACHNAME="${1}"
VORNAME="${2}"
funktiony()
{
echo "
FARBE='${1}'
ELEMENT='${2}'
VORNAME='${3}'
NACHNAME='${4}'
"
}
funktiony schwarze erde ${VORNAME} ${NACHNAME}
Hier sind die Parameter, die der Funktion übergeben werden, innerhalb der Funktion auch wieder als “$1“, “$2“, … verwendbar.
Entscheidungen
Bei Entscheideidungen muss man unterscheiden, ob man Zahlen mit oder ohne Kommastellen als Vergleich verwenden möchte!
Die "if"-Anweisung in der BASH kann nicht mit Kommastellen umgehen, in soeinem Fall muss man dann auf AWK zurückgreifen.
BASH
if [ "${1}" < 1 ] ; then
GR=klein
elif [ "${1}" < 2 ] ; then
GR=mittel
elif [ "${1}" < 3 ] ; then
GR=gross
else
GR="sehr gross"
fi
echo "${GR}"
AWK
# echo "1.5" | awk '{if ($1 < 3) GR="gross" ; if ($1 < 2) GR="mittel" ; if ($1 < 1) GR="klein" ; print $1"="GR}'
1.5=mittel
# echo "1.5" | awk '{if ($1 < 3) GR=3 ; if ($1 < 2) GR=2 ; if ($1 < 1) GR=1 ; print GR}'
2
Zählschleifen
BASH
Unter Linux ist die GNU Bourne-Again SHell unter /bin/bash die Standard-Shell, sie ist in erster Linie für die Konsolenarbeit verbesert worden. So verfühgt sie im Gegensatz zur Bourne SHell über eine Historie.
Die GNU Bourne-Again SHell verfühgt aber auch über zusätzliche Funktionen, die für die Arbeit mit Scripten wichtig sind.
Zum Beispiel funktioniert der kleine Time-Out-Zähler nur in der GNU Bourne-Again SHell, nicht jedoch in der Bourne SHell:
#!/usr/bin/env bash
WARTEZEIT="10"
while [ ! -e /tmp/datei ]
do
sleep 1
if [ "${WARTEZEIT}" -gt "0" ] ; then
WARTEZEIT=$((WARTEZEIT - 1))
else
touch /tmp/datei
fi
done
die folgenden beiden Zählschleifen funktionieren nur mit einer BASH, nicht mit einer "echten sh", wie z.B. die von FreeBSD (in Linux ist die sh ein Link auf die BASH):
> i=0 ; while (("$i"<"10")) ; do i="$((${i}+1))" ; echo "${i}" ; done
1
2
3
4
5
6
7
8
9
10
> i=10;while (("$i">"0")); do echo "${i}"; i="$((${i}-1))"; done
10
9
8
7
6
5
4
3
2
1
sh
Für die Bourne SHell muss das Kommando bc das rechnen im Script übernehmen:
#!/bin/sh
WARTEZEIT="10"
while [ ! -e /tmp/datei ]
do
sleep 1
if [ "${WARTEZEIT}" -gt "0" ] ; then
WARTEZEIT="$(echo "${WARTEZEIT} - 1" | bc)"
else
touch /tmp/datei
fi
done
oder das Kommando awk:
#!/bin/sh
WARTEZEIT="10"
while [ ! -e /tmp/datei ]
do
sleep 1
if [ "${WARTEZEIT}" -gt "0" ] ; then
WARTEZEIT="$(echo "${WARTEZEIT}" | awk '{print $1-1}')"
else
touch /tmp/datei
fi
done
bc
natürlicher Logarithmus aus 5:
> echo "l(5)" | bc -l 1.60943791243410037460
natürlicher Logarithmus aus 20:
> echo "l(20)" | bc -l 2.99573227355399099343
dezimaler Logarithmus 1000:
> echo "l(1000)/l(10)" | bc -l 3.00000000000000000000
binärer Logarithmus aus 8:
> echo "l(8)/l(2)" | bc -l 3.00000000000000000002
Zähler mit while und bc
Dieser Zähler ist zwar etwas umständlich, dafür funktioniert er aber auf jedem aktuellen Uni*-Like Betriebssystem, auf dem es das Programm "bc" gibt.
Man muss nur darauf achten, dass bc installiert ist. Das kleine Rechenprogramm gibt es aber schon lange für alle Uni*-Like Betriebssysteme.
vorwärts
# i=0;while(("$i"<"10"));do i="$(echo "1+$i"|bc)";echo "$i";done
1
2
3
4
5
6
7
8
9
10
rückwärts
# i=10;while(("$i">"0"));do i="$(echo "$i-1"|bc)";echo "$i";done
9
8
7
6
5
4
3
2
1
0
Zähler mit awk
Sonst kann man auch awk als Rechenknecht verwenden. AWK gibt es für alle Uni*-Like Betriebssysteme und ist eigentlich immer schon mit drauf.
vorwärts
# echo "10"|awk '{for(i=0;i<$1;i++) {print i}}'
0
1
2
3
4
5
6
7
8
9
# echo "10"|awk '{for(i=1;i<=$1;i++) {print i}}'
1
2
3
4
5
6
7
8
9
10
hier in Zweierschritten:
# echo "10"|awk '{for(i=1;i<=$1;i++) {if( i % 2 == 0) {print i}}}'
2
4
6
8
10
und jetzt mit fester Zahlenlänge:
# echo "10"|awk '{for(i=1;i<=$1;i++){printf("%.8u\n",i)}}'
00000001
00000002
00000003
00000004
00000005
00000006
00000007
00000008
00000009
00000010
rückwärts
# i=10 ; while (( "$i" > "0")) ; do i="$(echo "$i" | awk '{print $1-1}')" ; echo "$i" ; done
9
8
7
6
5
4
3
2
1
0
# i=10 ; until [ "$i" = "0" ] ; do i="$(echo "$i" | awk '{print $1-1}')" ; echo "$i" ; done
9
8
7
6
5
4
3
2
1
0
Oder man rechnet gleich komplett nur mit dem awk.
# echo "10"|awk '{for(i=$1;0<i;i--){print i}}'
10
9
8
7
6
5
4
3
2
1
und jetzt mit fester Zahlenlänge:
# echo "10"|awk '{for(i=$1;0<i;i--){printf("%.8u\n",i)}}'
00000010
00000009
00000008
00000007
00000006
00000005
00000004
00000003
00000002
00000001
Zähler mit seq
Dieser Befehl ist sehr bequem aber leider gibt es ihn nicht auf jedem System und ausserdem ist er in Scripten manchmal recht zickig.
vorwärts
# seq 1 10 1 2 3 4 5 6 7 8 9 10
rückwärts
# seq 1 10 | tac 10 9 8 7 6 5 4 3 2 1
Ausgabe mit fester Breite
# seq 1 10 | sed 's/.*/000000&/' | rev | cut -c 1-6 | rev 000001 000002 000003 000004 000005 000006 000007 000008 000009 000010
ewig warten bis ein Ereignis eintrifft
In diesem Fall wartet die Schleife darauf, dass ein Rechner wieder über das Netz erreichbar ist.
#!/bin/sh
START="1"
while [ "$?" != "0" -o "${START}" = "1" ]
do
START="0"
sleep 1
ping -c1 192.168.0.100
done
DATEI="diese_datei_wird_gleich_angelegt.tgz"
while [ -r "${DATEI}" ]
do
sleep 1
done
nur begrenzte Zeit warten bis ein Ereignis eintrifft
nur "180" Sekunden lang auf die Datei warten:
#!/bin/sh DATEI="diese_datei_wird_gleich_angelegt.tgz" ZAEHLER="180" while [ ! -r "${DATEI}" -a "${ZAEHLER}" -gt "0" ] do ZAEHLER="$(echo "${ZAEHLER}"|awk '{print $1-1}')" sleep 1 done
oder so:
#!/bin/sh DATEI="diese_datei_wird_gleich_angelegt.tgz" ZAEHLER="180" while [ "${ZAEHLER}" -gt "0" ] do ZAEHLER="$(echo "${ZAEHLER}"|awk '{print $1-1}')" if [ -r "${DATEI}" ] ; then ZAEHLER="0" fi sleep 1 done
maximal 180 Sekunden lang wartet, bis die Datenbank erreichbar ist:
#!/usr/bin/env bash MYSQL_LOGIN="--defaults-file=/root/.my.cnf" ZAEHLER="180" while [ "${ZAEHLER}" -gt "0" ] do ZAEHLER="$(echo "${ZAEHLER}"|awk '{print $1-1}')" if [ "$(mysqlshow ${MYSQL_LOGIN})" ] ; then ZAEHLER="0" fi sleep 1 done
Parameter mit BASH
#!/usr/bin/env bash
case "${1}" in
[Ee][Ii][Nn])
SCHALTEN="ein"
shift
;;
[Aa][Uu][Ss])
SCHALTEN="aus"
shift
;;
*)
echo "${0} ein"
echo "${0} aus"
shift
exit 1
;;
esac
#!/usr/bin/env bash
while [ "${#}" -ne "0" ]; do
case "${1}" in
-a)
OPTION_A=${2}
shift
;;
-b)
OPTION_B=${2}
shift
;;
-h)
echo "
HILFE:
${0} [Option]
-a [wert a]
-b [wert b]
"
exit 1
;;
*)
if [ "$(echo "${1}"|egrep '^-')" ] ; then
echo "Der Parameter '${1}' wird nicht unterstützt!"
fi
shift
;;
esac
done
echo "
OPTION_A=${OPTION_A}
OPTION_B=${OPTION_B}
"
Soll eine Fehlermeldung (unbound variable) erscheinen, wenn nicht alle Parameter übergeben wurden, dann muss "BASH" (in der ersten Zeile) mit der Optionen -u versehen werden.
statt so
#!/usr/bin/env bash
kann es zum Beispiel so aussehen:
#!/bin/bash -eu
Ein Beispiel mit getopts
https://linuxhint.com/getopts-usage-example-linux/
- /tmp/beispiel_getopts.sh
#!/bin/sh # wenn dieses Skript ohne Parameter aufgerufen wird # dann wird eine Hilfe ausgegeben if [ "x${1}" = x ] ; then echo "${0} -l -u [User] -h [Host]" exit 1 fi # der ":" besagt, dass dahinter ein Parameter erwartet wird while getopts "u: h: l" OPTION do case ${OPTION} in u) USER_NAME="${OPTARG}" ;; h) HOST_NAME="${OPTARG}" ;; l) STATUS="live" ;; esac done ### Der Parameter, der als Naechstes bearbeitet werden soll, wird bei einer Shell in der automatischen Variable OPTIND verwaltet. ### Der Wert dieser Variablen betraegt beim Aufruf erst einmal 1 – wird aber bei jedem weiteren getopts-Aufruf um 1 erhoeht. ### Wenn eine Kommandozeile mehrfach eingelesen werden soll, muss der Index manuell zurueckgesetzt werden. #OPTIND=1 echo " OPTIND='${OPTIND}' USER_NAME='${USER_NAME}' HOST_NAME='${HOST_NAME}' STATUS='${STATUS}' "
> /tmp/beispiel_getopts.sh -l -u abc -h system OPTIND='6' USER_NAME='abc' HOST_NAME='system' STATUS='live'
while ohne sub-shell
https://de.linux-console.net/?p=19969
Auf die Variablen, die in einer gewöhnlichen while-Schleife gesetzt werden,
hat man ausserhalb der Schleife keinen Zugriff, da die while-Schleife
gewöhnlich mit einer Pipe gefüttert wird.
Wegen der Pipe wird aber eine eigene Shell geöffnet und mit ihrem Ende enden auch
die Variablen in ihr.
Deshalb ist die Ausgabe dieses Skripts auch leer:
#!/usr/bin/env bash
VAR=""
echo "Test" | while read ZEILE
do
VAR="${ZEILE}"
done
echo "VAR='${VAR}'"
Dieses Skript liefert dagegen eine Ausgabe:
#!/usr/bin/env bash
VAR=""
while read ZEILE
do
VAR="${ZEILE}"
done < <(echo "Test")
echo "VAR='${VAR}'"
Keine Pipe,
keine Subshell,
keine gestobenen Variablen.
Allserdings funktioniert das auch nicht in vollem Umfang:
#!/usr/bin/env bash
VAR1=""
VAR2=""
VAR3=""
while read SPALTE1 SPALTE2 SPALTE3
do
VAR1="${SPALTE1}"
VAR2="${SPALTE2}"
VAR3="${SPALTE3}"
done < <(echo "Test")
echo "
VAR1='${VAR1}'
VAR2='${VAR2}'
VAR3='${VAR3}'
"
Wenn die Zeile gleichzeitig noch in Spalten aufgetrennt werden soll,
was ja eigentlich geht,
dann versagt diese Methode…
Probleme mit der while-Schleife
führt man in einer WHILE-Schleife komplexe Kommandos aus, dann wird oft nur das erste Kommando ausgeführt oder jedes 2. Kommando nicht ausgeführt:
# bei jeder 2. Zeile (Kommando) fehlen an Zeilenanfang, mehrere Zeichen, deshalb bricht es ab find . -type f -iname "Air Strike_*.mkv" | sed 's|^[.]/||' | sort | while read FILE do ffmpeg -i "${FILE}" -c:v mpeg4 -b:v 8192k -profile:v 15 -level 5 -g 300 -c:a ac3 -f avi -y "Test_${FILE}".avi done
Als Lösung kann man entweder den Umweg über eine Zwischendatei gehen, die dann als statisches Skript ausgeführt wird:
# bei jeder 2. Zeile (Kommando) fehlen an Zeilenanfang, mehrere Zeichen, deshalb bricht es ab find . -type f -iname "Air Strike_*.mkv" | sed 's|^[.]/||' | sort | while read FILE do Iecho "ffmpeg -i \"${FILE}\" -c:v mpeg4 -b:v 8192k -profile:v 15 -level 5 -g 300 -c:a ac3 -f avi -y \"Test_${FILE}\".avi" done > /tmp/statisches_Zwischen-Skript.sh bash /tmp/statisches_Zwischen-Skript.sh rm -f /tmp/statisches_Zwischen-Skript.sh
Oder man wählt die FOR-Schleife, muß dann aber den IFS verbiegen:
# funktioniert, wie erwartet IFS=$'\n' DATEIEN=($(find . -type f -iname "Air Strike_*.mkv" | sed 's|^[.]/||' | sort)) for FILE in "${DATEIEN[@]}" do ffmpeg -i "${FILE}" -c:v mpeg4 -b:v 8192k -profile:v 15 -level 5 -g 300 -c:a ac3 -f avi -y "Test_${FILE}".avi done
leere Unterverzeichnisse löschen
rmdir löscht nur leere Verzeichnisse, bei vollen wird eine Fehlermeldung ausgegeben:
> rmdir Verzeichnis/
ohne Fehlermeldung kann man das so machen:
> DIR="Verzeichnis/"; [ -d $DIR ] && [ $(ls -l $DIR | wc -l) -eq 1 ] && rmdir $DIR || :
leeren Unterverzeichnisse kann man mit find auch rekursiv löschen: leeren_unterverzeichnisse_loeschen
Alphabet generieren
> echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z
cooler Prompt
Wenn man als privilegierter Benutzer angemeldet ist, ist der Benutzername im Prompt pink, ist man als unprivilegierter Benutzer angemeldet ist, ist der Benutzername im Prompt hellblau. Der Hostname ist immer dunkelblau.
Andere Farben kann man nach belieben konfigurieren, die Farbtabelle ist u.a. hier hinterlegt: kommandozeile_cli
Die erste Zahl vor der Uhrzeit zeigt den Exit-Code an:
[root@rechner]---------------------------------------------------[0]-[0]-[14:14] [~]# false [root@rechner]---------------------------------------------------[1]-[0]-[14:14] [~]#
Die zweite Zahl gibt die Anzahl der im Hintergrund laufenden Job's an.
[root@rechner]---------------------------------------------------[0]-[0]-[14:15] [~]# sleep 60 ^Z [1]+ Angehalten sleep 60 [root@rechner]-------------------------------------------------[148]-[1]-[14:15] [~]# bg 1 [1]+ sleep 60 & [root@rechner]---------------------------------------------------[0]-[1]-[14:15] [~]# [root@rechner]---------------------------------------------------[0]-[1]-[14:17] [~]# [1]+ Fertig sleep 60 [root@rechner]---------------------------------------------------[0]-[1]-[14:17] [~]# [root@rechner]---------------------------------------------------[0]-[0]-[14:17] [~]#
mach_bash_prompt.sh
Dieses Skript nimmt den entsprechenden Eintrag in der datei ~/.bashrc vor
und erstellt die Datei~/.bash_prompt.
#!/usr/bin/env bash
echo "
[ -f ~/.bash_prompt ] && . ~/.bash_prompt || PS1='\\[\\033[1m\\]\\u@\\h\\[\\033[0m\\]:\\w\\$ '
export EDITOR=vi
" >> ~/.bashrc
(echo '
PROMPT_COLORS=${PROMPT_COLORS:-0}
prompt_command() {
local EC="$?"
case "$PROMPT_COLORS" in
*)
local CUSER="1;36"
local CHOST="1;34"
local CEC="1;34"
local CJOBS="1;34"
local CTIME="1;36"
local CDIR="0;35"
local CAT="0"
local CWARN="1;35"
local CDEF="0"
;;
esac
local R="\[\e[${CDEF}m\]"
local USER=$(whoami)
local HOSTNAME=$(hostname)
local JOBS=$(jobs|wc -l)
local PWD=$(pwd)
local TIME="$(date +"%F %T")"
PWD=${PWD/#$HOME/"~"}
[ "${TERM:0:5}" == "xterm" ] && echo -en "\033]0;$USER@$HOSTNAME:$PWD\007"
local TMP="[$USER@$HOSTNAME][$EC] [$JOBS] [$TIME]"
[ -n "$SSH_CONNECTION" ] && TMP="$TMP [ssh]"
local SP="-"
[ ${#TMP} -gt 0 ] && local SPACER=$(printf "%$((COLUMNS - ${#TMP}))s") || local SPACER=" "
SPACER=${SPACER// /$SP}
[ $EC -gt 0 ] && EC="\[\e[${CWARN}m\]$EC" || EC="\[\e[${CEC}m\]$EC"
[ $JOBS -gt 0 ] && JOBS="\[\e[${CWARN}m\]$JOBS" || JOBS="\[\e[${CEC}m\]$JOBS"
[ $UID -eq 0 ] && USER="\[\e[${CWARN}m\]$USER" || USER="\[\e[${CUSER}m\]$USER"
[ -n "$SSH_CONNECTION" ] && HOSTNAME="\[\e[${CHOST}m\]$HOSTNAME$R]$SP[\[\e[${CWARN}m\]ssh" || HOSTNAME="\[\e[${CHOST}m\]$HOSTNAME"
PS1="
$R[$USER\[\e[${CAT}m\]@$HOSTNAME$R]$SPACER\
[$EC$R]$SP[$JOBS$R]$SP[\[\e[${CTIME}m\]$TIME$R]
[\[\e[${CDIR}m\]$PWD$R]\\\$\[\e[0m\] "
}
PROMPT_COMMAND=prompt_command
[ "${TERM:0:6}" == "screen" ] && {
set_screen_title() {
while [ 1 ] ; do
case "$1" in
sudo|prompt_command|-*) shift ;;
*) break ;;
esac
done
echo -en "\033k${1:-bash}\033\\"
}
'
echo " trap 'set_screen_title \$BASH_COMMAND' DEBUG
}
") > ~/.bash_prompt
~/.bashrc
Dieser Eintrag überprüft, ob unsere spezielle BASH-Prompt-Datei vorhanden ist und bindet sie ein, wenn es sie hier gibt.
[ -f ~/.bash_prompt ] && . ~/.bash_prompt || PS1='\[\033[1m\]\u@\h\[\033[0m\]:\w\$ ' export EDITOR=vi
~/.bash_prompt
Diese Datei enthält die speziellen Einstellungen für unseren coolen Prompt.
PROMPT_COLORS=${PROMPT_COLORS:-0}
prompt_command() {
local EC="$?"
case "$PROMPT_COLORS" in
*)
local CUSER="1;36"
local CHOST="1;34"
local CEC="1;34"
local CJOBS="1;34"
local CTIME="1;36"
local CDIR="0;35"
local CAT="0"
local CWARN="1;35"
local CDEF="0"
;;
esac
local R="\[\e[${CDEF}m\]"
local USER=$(whoami)
local HOSTNAME=$(hostname)
local JOBS=$(jobs|wc -l)
local PWD=$(pwd)
local TIME=$(date +%H:%M)
PWD=${PWD/#$HOME/"~"}
[ "${TERM:0:5}" == "xterm" ] && echo -en "\033]0;$USER@$HOSTNAME:$PWD\007"
local TMP="[$USER@$HOSTNAME][$EC] [$JOBS] [$TIME]"
[ -n "$SSH_CONNECTION" ] && TMP="$TMP [ssh]"
local SP="-"
[ ${#TMP} -gt 0 ] && local SPACER=$(printf "%$((COLUMNS - ${#TMP}))s") || local SPACER=" "
SPACER=${SPACER// /$SP}
[ $EC -gt 0 ] && EC="\[\e[${CWARN}m\]$EC" || EC="\[\e[${CEC}m\]$EC"
[ $JOBS -gt 0 ] && JOBS="\[\e[${CWARN}m\]$JOBS" || JOBS="\[\e[${CEC}m\]$JOBS"
[ $UID -eq 0 ] && USER="\[\e[${CWARN}m\]$USER" || USER="\[\e[${CUSER}m\]$USER"
[ -n "$SSH_CONNECTION" ] && HOSTNAME="\[\e[${CHOST}m\]$HOSTNAME$R]$SP[\[\e[${CWARN}m\]ssh" || HOSTNAME="\[\e[${CHOST}m\]$HOSTNAME"
PS1="
$R[$USER\[\e[${CAT}m\]@$HOSTNAME$R]$SPACER\
[$EC$R]$SP[$JOBS$R]$SP[\[\e[${CTIME}m\]$TIME$R]
[\[\e[${CDIR}m\]$PWD$R]\\\$\[\e[0m\] "
}
PROMPT_COMMAND=prompt_command
[ "${TERM:0:6}" == "screen" ] && {
set_screen_title() {
while [ 1 ] ; do
case "$1" in
sudo|prompt_command|-*) shift ;;
*) break ;;
esac
done
echo -en "\033k${1:-bash}\033\\"
}
trap 'set_screen_title $BASH_COMMAND' DEBUG
}
Array
Array (also mit Index): ${array[0]}, ${array[1]}
Map (also mit Key) : ${array["one"]}, ${array["two"]}
Array ist wie eine Liste, in der jedes Element ein Index hat und Map ist einfach eine Liste von Key-Value-Pairs. Theoretisch ist ersteres eine Map, in der der Key ein Integer ist, der bei 0 startet.
mit explizitem Index
ReadArray
> readarray -t testarray < <(find Videos/ -type f)
> echo "${testarray[0]}"
> echo "${testarray[1]}"
> find Videos/ -type f > /tmp/test.txt
> readarray -t testarray < /tmp/test.txt
> echo "${testarray[0]}"
> echo "${testarray[1]}"
mit implizitem Index
> export ARRAY=(127 0 255)
> echo ${ARRAY[@]}
127 0 255
> echo ${#ARRAY[@]}
3
> echo ${#ARRAY[0]}
127
> echo ${#ARRAY[1]}
0
> echo ${#ARRAY[2]}
255
> testarray=($(find Videos/ -type f))
> echo "${testarray[0]}"
> echo "${testarray[1]}"
ACHTUNG!
Es funktioniert mit testarray="$(find Videos/ -type f)" und testarray="($(find Videos/ -type f))" anders und der Index ist, bei diesen beiden, nicht das, was man erwartet!
