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.
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 \03338 (Vordergrundfarbe) und 48 (Hintergrundfarbe)2 (RGB Format verwenden)24 / 3 = 8-bitVariablen:
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!
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
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
> 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
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.
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.
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}"
# 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
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
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
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
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
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.
# i=0;while(("$i"<"10"));do i="$(echo "1+$i"|bc)";echo "$i";done
1
2
3
4
5
6
7
8
9
10
# i=10;while(("$i">"0"));do i="$(echo "$i-1"|bc)";echo "$i";done
9
8
7
6
5
4
3
2
1
0
Sonst kann man auch awk als Rechenknecht verwenden. AWK gibt es für alle Uni*-Like Betriebssysteme und ist eigentlich immer schon mit drauf.
# 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
# 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
Dieser Befehl ist sehr bequem aber leider gibt es ihn nicht auf jedem System und ausserdem ist er in Scripten manchmal recht zickig.
# seq 1 10 1 2 3 4 5 6 7 8 9 10
# seq 1 10 | tac 10 9 8 7 6 5 4 3 2 1
# seq 1 10 | sed 's/.*/000000&/' | rev | cut -c 1-6 | rev 000001 000002 000003 000004 000005 000006 000007 000008 000009 000010
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 "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
#!/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
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'
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…
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
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
> 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
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] [~]#
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
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
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 (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.
> 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]}"
> 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!