====== 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.
[[http://www.linux-praxis.de/linux1/shell2_7.html]]
[[http://www.netzmafia.de/skripten/unix/unix2.html]]
===== farbige Textausgabe (24bit Farben) =====
* [[https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters|SGR Parameter]]
* [[https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit|24-bit Farben]]
* [[https://google.com/search?q=color+picker|Color Picker]]
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) und ''48'' (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 =====
[[https://mywiki.wooledge.org/BashGuide/Patterns|BashGuide/Patterns]]
==== 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) =====
[[https://www.cyberciti.biz/faq/unix-linux-bash-while-read-function-define-ifs-delimiter/|Bash / KSH: Define Delimiter (IFS) While Using read Command]]
anzeigen
cat -etv
===== Remote Procedure Call - RPC =====
* [[https://gist.github.com/derekp7|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).
* [[https://gist.github.com/derekp7/9978986|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.__
#!/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
> echo "a=1; b=2; c=3; print \"a=\", a, \" b=\", b, \" c=\", c; print \"\nSumme:\", a + b + c;print \"\n\""
a=1; b=2; c=3; print "a=", a, " b=", b, " c=", c; print "\nSumme:", a + b + c;print "\n"
> echo "a=1; b=2; c=3; print \"a=\", a, \" b=\", b, \" c=\", c; print \"\nSumme:\", a + b + c;print \"\n\"" | bc -lq
a=1 b=2 c=3
Summe:6
=== Zahlen von eine Basis in eine andere Basis umrechnen ===
ibase = In welcher Basis verstehe ich deine Eingaben?
obase = In welcher Basis soll ich die Ergebnisse ausgeben?
> echo "ibase=10; obase=2; 255" | bc
11111111
> echo "255" | sed "s/.*/ibase=10; obase=2; &/" | bc
11111111
> vim calc.bc
ibase=10;
obase=2;
> echo "255" | bc calc.bc
11111111
obase = read();
n = read();
print n;
print "\n"
> for BASIS in 2 3 5 7 8 12 16; do echo "${BASIS} 123" | tr ' ' '\n' | bc -q ./Zahlenbasis.bc; done
1111011
11120
443
234
173
A3
7B
=== 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
#!/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/]]
#!/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:
#!/usr/bin/env bash
# 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:
#!/usr/bin/env bash
# funktioniert, wie erwartet
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, dann muß man aber den ''IFS'' verbiegen, um Dateien mit Leerzeichen verarbeiten zu können:
#!/usr/bin/env bash
# funktioniert, wie erwartet, aber Dateien mit Leerzeichen kann man so nur mit verbogenem IFS verarbeiten
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: [[find#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: [[Terminaleinstellungen#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
> arrayLaenge=${#ARRAY[@]}
> echo "Das Array enthält '${arrayLaenge}' Elemente."
Das Array enthält '3' Elemente.
> 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!__