Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
|$1 $2 $3 ...|Argument 1, 2, 3, das dem Programm mitgegeben wurde|
|$*|alle Argumente, durch Leerzeichen getrennt|
|$@|alle Argumente, wobei ein Argument auch Leerzeichen enthalten könnte|
Hier noch einige Tricks um die Funktionalität der Bash auf der Kommandozeile voll auszunutzen beziehungsweise durch eigene Scripte noch zu verbessern!
!Scripte für die Kommandozeile (Author Andreas Straka, GPL open source)
Kopiere dir die Befehle in eine neue Datei mit dem Namen der Überschrift, mach sie ausführbar und speichere sie in deinem Scripteordner.
!!path
{{{
#!/bin/bash
#
# gibt fuer alle Dateien und Verzeichnisse im aktuellen Verzeichnis den absoluten Pfad aus,
# oder fuer die angegebenen Dateien oder Verzeichnisse
#
# 22.04.2011, Andreas Straka, Erstellung
if [[ "$1" != "" ]]
then
for i in $*
do
readlink -f $i
done
else
for i in *
readlink -f "$i"
done
fi
}}}
Dieses Programm ist sehr zu empfehlen. Am besten ein alias pa definieren. Tip: readlink gibt eigentlich nur den gültigen absoluten Pfad, egal ob die Datei exisitiert oder nicht!
!Beispiel 1
Script verarbeitet viele Dateien mit Tabellen in einem bestimmten Format. Ziel ist es den Header zu entfernen der mit BEGIN anfängt und mit END aufhört. Ebenso soll danach die erste Zeite der Tabelle entfernt werden. Anschließend wir nur ein Teil der Tabelle ausgegeben, die 1.,7.,und 8. Spalte. (Frequenz über komplexe Beschleunigung). Die veränderten Dateien werden in ein Unterverzeichnis META geschrieben mit modifiziertem Dateinamen.
{{{
mkdir META
for i in $(ls *.GID)
do
name=$(echo $i | sed -e "s/_Time.GID//g" | sed -e "s/usr1_//g")
sed '/BEGIN/,/END/d' $i | sed -e '1,1d' | gawk '{ print $1,$7,$8}' > META/$name
done
}}}
{{{
BEGIN
CHANNEL = ['Freq', &
'Ordr', &
'Order', &
'Onice', &
'Disp-m_M', &
'Disp-m_F', &
END
0 0 0 0 0 0 -54.863765
12.946811 0.12500595 0.13 0.125 -16.183387 -0.0010028339 109.72755
25.893621 0.25001191 0.25 0.25 -124.22625 92.447254 0.00043468272
}}}
OUTPUT
{{{
12.946811 0.12500595 0.13 0.125 -16.183387 -0.0010028339 109.72755
25.893621 0.25001191 0.25 0.25 -124.22625 92.447254 0.00043468272
}}}
!!!Scriptparameter als Optionen
{{{
hilfe()
{
cat <<"EOF" >&2
Programmaufruf: $0 -i Inputdatei -o Outputdatei [-v]
EOF
exit 1
}
while getopts "vi:o:" opt
do
case "$opt" in
v ) OPTION_VERBOSE=0 ;;
i ) INPUT="$OPTARG" ;;
o ) OUTPUT="$OPTARG" ;;
? ) hilfe
esac
done
shift $(( $OPTIND - 1 ))
}}}
Anstelle der Ausgabe der Hilfe und des Programmabbruchs kann man natürlich auch die notwendigen Daten vom Benutzer interaktiv abfragen:
!!!Benutzereingabe mit read
{{{
echo -n "neue Variante: "; read variante
if [[ "$variante" == "" ]]
then
echo "Keine Eingabe. Abbruch!" >&2
exit 0
fi
}}}
!!!Auswahl mit Select-Anweisung
{{{
PS3="Auswahl: "
select auswahl in *
do
echo "Auswahl: $auswahl"
break
done
}}}
Ohne break wiederholt sich die Abfrage, bis man Strg+d drückt.
Background: #fff
Foreground: #000
PrimaryPale: #999933
PrimaryLight: #008822
PrimaryMid: #003300
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #99ff00
SecondaryMid: #003300
SecondaryDark: #003300
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
<<tiddler TemplateColorPaletteView with:ColorPalette>>
!Dateien lesen und verarbeiten
{{{
for i in $(cat datei)
do
echo $i
done
}}}
{{{
while read zeile
do
echo $zeile
done < $datei
}}}
Datei in ein Array lesen:
{{{
while read zeile[$i]
do
let i++
done << $datei
}}}
!Datei schreiben innerhalb des Scripts
{{{
cat <<EOF >/tmp/jobinfos.tmp
source $path_audi
destination /home/projekte/AUDI/AU495/P_FREI/DYNAMIK/CAE/ERGEBNISSE
jobname $jobname_found
jobid $jobid
project $DEFAULT_PROJECT_CB
EOF
}}}
Achtung: Wenn EOF in Anführungszeichen steht werden Variablen nicht ersetzt.
version.extensions.DisableWikiLinksPlugin= {major: 1, minor: 6, revision: 0, date: new Date(2008,7,22)};
if (config.options.chkDisableNonExistingWikiLinks==undefined) config.options.chkDisableNonExistingWikiLinks= false;
if (config.options.chkDisableWikiLinks==undefined) config.options.chkDisableWikiLinks=false;
if (config.options.txtDisableWikiLinksList==undefined) config.options.txtDisableWikiLinksList="DisableWikiLinksList";
if (config.options.chkAllowLinksFromShadowTiddlers==undefined) config.options.chkAllowLinksFromShadowTiddlers=true;
if (config.options.txtDisableWikiLinksTag==undefined) config.options.txtDisableWikiLinksTag="excludeWikiWords";
// find the formatter for wikiLink and replace handler with 'pass-thru' rendering
initDisableWikiLinksFormatter();
function initDisableWikiLinksFormatter() {
for (var i=0; i<config.formatters.length && config.formatters[i].name!="wikiLink"; i++);
config.formatters[i].coreHandler=config.formatters[i].handler;
config.formatters[i].handler=function(w) {
// supress any leading "~" (if present)
var skip=(w.matchText.substr(0,1)==config.textPrimitives.unWikiLink)?1:0;
var title=w.matchText.substr(skip);
var exists=store.tiddlerExists(title);
var inShadow=w.tiddler && store.isShadowTiddler(w.tiddler.title);
// check for excluded Tiddler
if (w.tiddler && w.tiddler.isTagged(config.options.txtDisableWikiLinksTag))
{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
// check for specific excluded wiki words
var t=store.getTiddlerText(config.options.txtDisableWikiLinksList);
if (t && t.length && t.indexOf(w.matchText)!=-1)
{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
// if not disabling links from shadows (default setting)
if (config.options.chkAllowLinksFromShadowTiddlers && inShadow)
return this.coreHandler(w);
// check for non-existing non-shadow tiddler
if (config.options.chkDisableNonExistingWikiLinks && !exists)
{ w.outputText(w.output,w.matchStart+skip,w.nextMatch); return; }
// if not enabled, just do standard WikiWord link formatting
if (!config.options.chkDisableWikiLinks)
return this.coreHandler(w);
// just return text without linking
w.outputText(w.output,w.matchStart+skip,w.nextMatch)
}
}
Tiddler.prototype.coreAutoLinkWikiWords = Tiddler.prototype.autoLinkWikiWords;
Tiddler.prototype.autoLinkWikiWords = function()
{
// if all automatic links are not disabled, just return results from core function
if (!config.options.chkDisableWikiLinks)
return this.coreAutoLinkWikiWords.apply(this,arguments);
return false;
}
Tiddler.prototype.disableWikiLinks_changed = Tiddler.prototype.changed;
Tiddler.prototype.changed = function()
{
this.disableWikiLinks_changed.apply(this,arguments);
// remove excluded wiki words from links array
var t=store.getTiddlerText(config.options.txtDisableWikiLinksList,"").readBracketedList();
if (t.length) for (var i=0; i<t.length; i++)
if (this.links.contains(t[i]))
this.links.splice(this.links.indexOf(t[i]),1);
};
test -e ~ANSA_Input.log && echo Logfile existiert
!!!if-Anweisung
{{{
if bedingung
then
...code...
fi
}}}
{{{
if bedingung
then
...code...
elif bedingung
...code...
else
...code...
fi
}}}
In der ~Shell-Programmierung ist eine Bedingung war, wenn sie den Wert 0 liefert!
!!!!Häufige if-Schleifen-Bedingungen
<<<
@@<nowiki>Regel: [ ] für Dateien, [[ ]] für Text, (( )) für Zahlen</nowiki>@@
<<<
| [ -e datei ] |prüft ob die Datei exisitert; alternativ für -e, -> ''siehe Dateitests'' unten; logische Operatoren -a und -o (Kommando test)|
| (( "$x" == "$y" )) |Zahlenvergleiche: ==, !=, <, >, <=, >= (Kommando let)|
| <nowiki>[[ "$wort" == "" ]]</nowiki> |Zeichenkettenvergleiche == != < >, -z leer oder nicht existierend, -n nicht leer|
''Dateitests:
-e existiert
-d ist ein Verzeichnis
-f ist eine reguläre Datei
-L ist ein symbolischer Link
-rwx ist lesbar/schreibbar/ausführbar''
| <nowiki>[[ "$wort" == muster ]] </nowiki> |<nowiki>Mustervergleich; Beispiel: [[ "$datei" == *dat ]] Datei endet mit dat; ? einzelnes Zeichen [] Zeichengruppe, z.B. [0-9] für Zahl</nowiki>|
| <nowiki>[[ "$a" == "$b" && "$c" == "$d" ]]</nowiki> |<nowiki>logische Operatoren == && || ! für '''[[ ]]'''-Bedingungen, aber auch ausserhalb der Klammern für Kommandos allgemein</nowiki>|
{{{
if (( $zahl > 10 )) && [[ "$text" == "yes ]]
then
...code...
fi
}}}
<<<
Anmerkung:
(( )) ist eine Bedingung für Zahlen, [[ ]] für Text, [ ] für Dateien, was den Code recht übersichtlich macht.
Deshalb die alte Vorgehensweise wegen einheitlicher Vorgehensweise nicht nutzen:
| [ "$var" != "" ] |$var ist keine leere Variable oder Zeichenkette, alternativ -z "$var"|
| [ "$x" -eq "$y" ] |Zahlenvergleiche (alte Form): -ne not equal, -lt lower than, -gt greater than, -le lower or equal, -ge greater or equal (Kommando test)|
<<<
!!!case-Anweisung
{{{
case "$antwort" in
ja)
...code...
;;
nein)
...code...
;;
*) # wie else bei if
...code...
;;
esac
}}}
!!!Definition
Die Definitionen der Funktionen stehen immer am Anfang des Scripts. Hier ein Beispiel mit Übergabe von zwei Argumenten.
{{{
funktionsname()
{
funktionsargument1=$1
funktionsargument2=$2
...code...
return $returnvalue
}
}}}
!!!Aufruf
Der Aufruf der Funktion erfolgt wie bei allen anderen Shell-Kommandos.
{{{
funktionsname arg1 arg2
}}}
!!!Returnvalue
Der Returnvalue wird genutzt um die Funktion z.B. in if-Abfragen zu verwenden.
Ist die Funktion erfolgreich, wird der Returnvalue 0 zurückgeliefert, ansonsten ein Wert größer null.
{{{
if funktionsname arg1 arg2
then
echo alles OK
fi
}}}
Dies ist konsequenterweise auch bei Bedingungen der Fall, 0 ist wahr.
Hier gehe ich auf einige Grundlagen ein, die der Vollständigkeit dienen sollen.
Jedes Script ist eine normale Text-Datei, die mit {{{chmod +x scripname}}} ausführbar gemacht wird.
Danach kann man das Script mit {{{./scriptname}}} starten.
{{{
#!/bin/bash
}}}
Dies steht in der ersten Zeile eines Bash-Scripts, und gibt den Pfad zur Bash an. Evtl. muss er bei anderen Linux-Distributionen angepasst werden.
!!!Variablenzuweisung und Benutzung
{{{
a="Hallo"
echo $a
b=9
echo $b
c=$(pwd)
}}}
Der Ausdruck $() ersetzt die früher benutzte ~Kommando-Substitution mit Backticks: {{{`commando`}}}.
Alles was die Befehle innerhalb der Klammer an Text ausgeben, wird in die Befehlszeile eingesetzt, d.h. hier wird der aktuelle Pfad in der Variable c gespeichert.
{{{
dateiname_neu=${dateiname}.sik
}}}
Die ausführliche Schreibweise für Variablen ist {{{${Variablenname}}}} und dient zur Abgrenzung des Variabennamens von weiterem Text oder ähnlichem.
!!!Spezialvariaben
Diese Spezialvariablen muss man kennen:
|$0|Pfad (inklusive Namen) des aktuell laufenden Scriptes|
|$1, $2, $3, ... ${10}, ...|Programmargumente|
|$*|alle Argumente, durch Leerzeichen getrennt|
|$@|alle Argumente, wobei ein Argument auch Leerzeichen enthalten könnte|
|$#|Anzahl der Programmargumente|
|$?|Exitstatus des zuletzt ausgeführten Befehls|
|$$|Prozess-ID des Programms, wird anstelle einer Randomzahl oft zur eindeutigen Namenvergabe verwendet|
!!!Ausgabeumleitungen
Viele Unixprogramme geben das Ergebnis ihrer Datenverarbeitung auf die Konsole aus, d.h. man braucht etwas um diese Ausgabe in eine Datei umzulenken und dort zu speichern.
Dies erreicht man durch die sogenannte Umleitung des Kanals, des Datenstroms mittels > < >>.
Umlenkung der Standardausgabe eines Befehls (was in die Konsole geschrieben wird, sofern keine Fehlerausgabe)
{{{
cat datei1 datei2 > datei3
}}}
Text an eine Datei anhängen
{{{
echo neue Zeile >> datei
}}}
Ausgabe in den Fehlerkanal 2
{{{
echo "Programmaufruf: $0 Argument1 Argument2" >&2
}}}
Umlenkung des Fehlerkanals 2 in eine Logdatei
{{{
echo "Fehler: Kann Datei nicht schreiben" 2>>fehler.log
}}}
Umlenkung der Standard-Ausgabe und Fehlerausgabe in eine Datei
{{{
kommando arg1 arg2 > ausgabedatei.txt 2>&1
}}}
Eine Pipe | leitet die Programmausgabe eines Programms an das nächste weiter. Viele Unix-Programme können dies verarbeiten.
{{{
cat datei | grep hallo > ergebnis.txt
}}}
!!!Wichtige ~Standard-Kommandos
...die viele für gewöhnlich bei einem interaktiven ~Shell-Gebrauch nicht benutzen.
|echo text|Ausgabe von text auf der Konsole, Option -n unterdrückt den Zeilenvorsprung|
|cat datei|gibt die Datei auf der Konsole aus|
|{{{cat datei | sed -e "s/alte_Zeichenkette/neue_Zeichenkette/g"}}}|ersetzt alte Zeichenkette durch neue Zeichenkette in der Datei|
|{{{echo Zeichenkette | sed -e "s/alte_Zeichenkette/neue_Zeichenkette/g"}}}|ersetzt alte Zeichenkette durch neue Zeichenkette, für Zeichenketten in Variablen|
Hier einige Konventionen speziell zu meiner Scriptsammlung
|$OPTION_VERBOSE|Diese Variable wird bei mir benutzt um vermehrt Programmausgaben zu generieren. Value für verbose an: 1,2,3 Wenn sie nicht gesetzt ist macht das auch nichts.|
[[Bash Reference Manual|http://www.gnu.org/software/bash/manual/bash.html]] - Offizielle komplette Referenz der neuesten Bash-Version
[[Wicked Cool Shell Scripts|http://intuitive.com/wicked/wicked-cool-shell-script-library.shtml]] - Einige sehr brauchbare bash-Scripte zum Vertiefen der Kenntnisse
[[Advanced Shell Scripting Guide|http://tldp.org/LDP/abs/html/index.html]] - Alle Möglichkeiten der Bash mit vielen Beispielen, leichter erklärt als im Reference Manual
[[Bash Guide|http://mywiki.wooledge.org/BashGuide]] - Bash-Einführung
Zum Programmieren der Bash gehört natürlich auch die Kenntnis und der Umgang mit den typischen Unix-Programmen.
Hierfür gibt es eigene Internetseiten und Bücher.
Hier habe ich einige Code-Schnipsel gesammelt, die man zum Programmieren benötigt, und weitere Unix-befehle benutzen.
!Datum
{{{
datum=$(date +"%y%m%d")
backupfile=$PFAD_BACKUP/${datum}_$$_$(basename $file)
}}}
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
major: 1, minor: 1, revision: 0,
date: new Date("mar 17, 2007"),
source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};
if (!window.bidix) window.bidix = {}; // bidix namespace
if (!bidix.core) bidix.core = {};
bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){
url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
}
return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
[[Vorwort]]
[[Links]]
!!Theorie
[[Grundlagen]]
[[Fallunterscheidung]]
[[Schleifen]]
[[Funktionen]]
[[Variablen, Datentypen]]
[[Rechnen und Zählen]]
[[Zeichenketten]]
[[Dateiverarbeitung]]
[[Benutzerinteraktion]]
[[Muster]]
[[Linux-Befehle]]
!!Rezepte
[[temporäre Dateien]]
!!Sonstiges
[[Konventionen]]
[[Programmierstil]]
[[Bash-Kommandozeile]]
[[Übungen]]
[[WelcomeToTiddlyspot]]
Alternative Muster: {{{prefix{alternative1,alternative2}suffix}}}
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
major: 1, minor: 0, revision: 2,
date: new Date("Apr 19, 2007"),
source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
author: 'BidiX (BidiX (at) bidix (dot) info',
license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
coreVersion: '2.2.0 (Beta 5)'
};
config.macros.option.passwordCheckboxLabel = "Save this password on this computer";
config.macros.option.passwordInputType = "password"; // password | text
setStylesheet(".pasOptionInput {width: 11em;}\n","passwordInputTypeStyle");
merge(config.macros.option.types, {
'pas': {
elementType: "input",
valueField: "value",
eventName: "onkeyup",
className: "pasOptionInput",
typeValue: config.macros.option.passwordInputType,
create: function(place,type,opt,className,desc) {
// password field
config.macros.option.genericCreate(place,'pas',opt,className,desc);
// checkbox linked with this password "save this password on this computer"
config.macros.option.genericCreate(place,'chk','chk'+opt,className,desc);
// text savePasswordCheckboxLabel
place.appendChild(document.createTextNode(config.macros.option.passwordCheckboxLabel));
},
onChange: config.macros.option.genericOnChange
}
});
merge(config.optionHandlers['chk'], {
get: function(name) {
// is there an option linked with this chk ?
var opt = name.substr(3);
if (config.options[opt])
saveOptionCookie(opt);
return config.options[name] ? "true" : "false";
}
});
merge(config.optionHandlers, {
'pas': {
get: function(name) {
if (config.options["chk"+name]) {
return encodeCookie(config.options[name].toString());
} else {
return "";
}
},
set: function(name,value) {config.options[name] = decodeCookie(value);}
}
});
// need to reload options to load passwordOptions
loadOptionsCookie();
/*
if (!config.options['pasPassword'])
config.options['pasPassword'] = '';
merge(config.optionsDesc,{
pasPassword: "Test password"
});
*/
//}}}
!Beschreibung des Codes
1. Immer das Script durch einen Header beginnen der folgende Informationen enthält:
*Scriptname
*Beschreibung
*Syntax
*Ausführlichere Dokumentation der Features
*Version, Datum, Author
*Version, Datum, Author der Änderung, Beschreibung der Änderung
2. Auch Funktionen durch einen Header beschreiben
*Funktionsname
*Beschreibung
*Parameter
*Rückgabewerte
*Version, Datum, Author
3. Code ausführlich kommentieren
!Variablen
* lange bechreibende Namen
* Variablen anstelle von festen Bezeichnungen verwenden, wie z.B. Dateinamen
* Variablen wenn möglich am Anfang des Scripts belegen
<<<
''@@Regel: Zählen und rechnen mit Ganzzahlen mit let, einfache Rechnungen mit bc, sonsitge Rechnungen z.B. mit perl@@''
<<<
!!!Ganzzahlenarithmetik + - / * %
{{{
a=1
b=5
c=(($a+$b)) #oder
let c=$a+$b
}}}
!!!Zählen
{{{
let d=$d+1
let anzahl++
}}}
!!!Fließkommazahlenarithmetik
{{{
a=1.2; b=4.3
c=$(echo $a + $b | bc)
}}}
!!!Potenzieren, Wurzelziehen, Klammerrechnung
{{{
echo 4^2 | bc
echo 'sqrt(9.0)' | bc
echo $a \* \( $b - 3 \) | bc
}}}
Darauf achten dass Sonderzeichen wie * oder ( vor der Shell durch \ maskiert werden. Um Ganzzahlenarithmetik zu vermeiden, Fließkommazahlen auch bei runden Zahlen verwenden: 3.0/5
!!!beliebig komplexe Rechnungen mit perl
{{{
c=$(perl -e "log($a+$b)")
y_neu=$(perl -e "print "%f", ($y-$y_ref)/$y_ref*100")
}}}
einige mathematische Perlfunktionen
*$x**2 Potenzbildung
*abs($x) Absolutwert von $x
*atan2($x,$y) Arcustangens von $x/$y (zwischen -pi und +pi)
*cos($x) Cosinus von $x (im Bogenmaß)
*exp($x) Exponentialfunktion ("e hoch $x", wobei e=2,71828...)
*log($x) Natürlicher Logarithmus von $x
*sin($x) Sinus-Funktion (im Bogenmaß)
*sqrt($x) Quadratwurzel
Für alle Schleifen gilt:
|{{{break}}}|beendet die gesamte Schleifenanweisung vorzeitig|
|{{{continue}}}|springt zum Ende der Schleife|
!!!for-Schleife
{{{
for i in $words
do
echo $i
done
}}}
{{{
for i in datei1 datei2 datei3
...
for i in $(find . -name "*dat")
...
for i in *dat
...
for i in {1..10} #{Startwert..Endwert..Inkrement}
...
for (( i=1 ; i <= 10 ; i++ ))
...
}}}
!!!while-Schleife
{{{
while bedingung
do
...code...
done
}}}
{{{
until bedingung
do
...
done
}}}
Endlosschleife
{{{
while true
do
...
sleep $sekunden_pause
done
}}}
/***
|Name|SearchOptionsPlugin|
|Source|http://www.TiddlyTools.com/#SearchOptionsPlugin|
|Documentation|http://www.TiddlyTools.com/#SearchOptionsPluginInfo|
|Version|3.0.9|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements|
|~CoreVersion|2.1|
|Type|plugin|
|Description|extend core search function with additional user-configurable options|
Adds extra options to core search function including selecting which data items to search, enabling/disabling incremental key-by-key searches, and generating a ''list of matching tiddlers'' instead of immediately displaying all matches. This plugin also adds syntax for rendering 'search links' within tiddler content to embed one-click searches using pre-defined 'hard-coded' search terms.
!!!!!Documentation
>see [[SearchOptionsPluginInfo]]
!!!!!Configuration
<<<
<<tiddler SearchOptions>>
<<option chkSearchResultsOptions>> Include {{{options...}}} slider in "search again" form
<<<
!!!!!Revisions
<<<
2011.03.18 3.0.9 moved configuration controls to [[SearchOptions]] shadow tiddler
|please see [[SearchOptionsPluginInfo]] for additional revision details|
2005.10.18 1.0.0 Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.SearchOptionsPlugin= {major: 3, minor: 0, revision: 9, date: new Date(2011,3,18)};
//}}}
//{{{
var defaults={
chkSearchTitles: true,
chkSearchText: true,
chkSearchTags: true,
chkSearchFields: true,
chkSearchTitlesFirst: true,
chkSearchList: true,
chkSearchHighlight: true,
chkSearchListTiddler: false,
chkSearchByDate: false,
chkIncrementalSearch: true,
chkSearchShadows: true,
chkSearchOpenTiddlers: false,
chkSearchResultsOptions:true,
chkSearchExcludeTags: true,
txtSearchExcludeTags: 'excludeSearch',
txtIncrementalSearchDelay: 500,
txtIncrementalSearchMin: 3
}; for (var id in defaults) if (config.options[id]===undefined)
config.options[id]=defaults[id];
if (config.macros.search.reportTitle==undefined)
config.macros.search.reportTitle="SearchResults"; // note: not a cookie!
config.macros.search.label+="\xa0"; // a little bit of space just because it looks better
//}}}
// // searchLink: {{{[search[text to find]] OR [search[text to display|text to find]]}}}
//{{{
config.formatters.push( {
name: "searchLink",
match: "\\[search\\[",
lookaheadRegExp: /\[search\[(.*?)(?:\|(.*?))?\]\]/mg,
prompt: "search for: '%0'",
handler: function(w)
{
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var label=lookaheadMatch[1];
var text=lookaheadMatch[2]||label;
var prompt=this.prompt.format([text]);
var btn=createTiddlyButton(w.output,label,prompt,
function(){story.search(this.getAttribute("searchText"))},"searchLink");
btn.setAttribute("searchText",text);
w.nextMatch = this.lookaheadRegExp.lastIndex;
}
}
});
//}}}
// // incremental search uses option settings instead of hard-coded delay and minimum input values
//{{{
var fn=config.macros.search.onKeyPress;
fn=fn.toString().replace(/500/g, "config.options.txtIncrementalSearchDelay||500");
fn=fn.toString().replace(/> 2/g, ">=(config.options.txtIncrementalSearchMin||3)");
eval("config.macros.search.onKeyPress="+fn);
//}}}
// // REPLACE story.search() for option to "show search results in a list"
//{{{
Story.prototype.search = function(text,useCaseSensitive,useRegExp)
{
var co=config.options; // abbrev
var re=new RegExp(useRegExp ? text : text.escapeRegExp(),useCaseSensitive ? "mg" : "img");
if (config.options.chkSearchHighlight) highlightHack=re;
var matches = store.search(re,co.chkSearchByDate?"modified":"title","");
if (co.chkSearchByDate) matches=matches.reverse(); // most recent first
var q = useRegExp ? "/" : "'";
clearMessage();
if (!matches.length) {
if (co.chkSearchListTiddler) discardSearchResults();
displayMessage(config.macros.search.failureMsg.format([q+text+q]));
} else {
if (co.chkSearchList||co.chkSearchListTiddler)
reportSearchResults(text,matches);
else {
var titles = []; for(var t=0; t<matches.length; t++) titles.push(matches[t].title);
this.closeAllTiddlers(); story.displayTiddlers(null,titles);
displayMessage(config.macros.search.successMsg.format([matches.length, q+text+q]));
}
}
highlightHack = null;
}
//}}}
// // REPLACE store.search() for enhanced searching/sorting options
//{{{
TiddlyWiki.prototype.search = function(searchRegExp,sortField,excludeTag,match)
{
var co=config.options; // abbrev
var tids = this.reverseLookup("tags",excludeTag,!!match,sortField);
var opened=[]; story.forEachTiddler(function(tid,elem){opened.push(tid);});
// eliminate tiddlers tagged with excluded tags
if (co.chkSearchExcludeTags&&co.txtSearchExcludeTags.length) {
var ex=co.txtSearchExcludeTags.readBracketedList();
var temp=[]; for(var t=tids.length-1; t>=0; t--)
if (!tids[t].tags.containsAny(ex)) temp.push(tids[t]);
tids=temp;
}
// scan for matching titles first...
var results = [];
if (co.chkSearchTitles) {
for(var t=0; t<tids.length; t++) {
if (co.chkSearchOpenTiddlers && !opened.contains(tids[t].title)) continue;
if(tids[t].title.search(searchRegExp)!=-1) results.push(tids[t]);
}
if (co.chkSearchShadows)
for (var t in config.shadowTiddlers) {
if (co.chkSearchOpenTiddlers && !opened.contains(t)) continue;
if ((t.search(searchRegExp)!=-1) && !store.tiddlerExists(t))
results.push((new Tiddler()).assign(t,config.shadowTiddlers[t]));
}
}
// then scan for matching text, tags, or field data
for(var t=0; t<tids.length; t++) {
if (co.chkSearchOpenTiddlers && !opened.contains(tids[t].title)) continue;
if (co.chkSearchText && tids[t].text.search(searchRegExp)!=-1)
results.pushUnique(tids[t]);
if (co.chkSearchTags && tids[t].tags.join(" ").search(searchRegExp)!=-1)
results.pushUnique(tids[t]);
if (co.chkSearchFields && store.forEachField!=undefined)
store.forEachField(tids[t],
function(tid,field,val) {
if (val.search(searchRegExp)!=-1) results.pushUnique(tids[t]);
},
true); // extended fields only
}
// then check for matching text in shadows
if (co.chkSearchShadows)
for (var t in config.shadowTiddlers) {
if (co.chkSearchOpenTiddlers && !opened.contains(t)) continue;
if ((config.shadowTiddlers[t].search(searchRegExp)!=-1) && !store.tiddlerExists(t))
results.pushUnique((new Tiddler()).assign(t,config.shadowTiddlers[t]));
}
// if not 'titles first', or sorting by modification date,
// re-sort results to so titles, text, tag and field matches are mixed together
if(!sortField) sortField = "title";
var bySortField=function(a,b){
if(a[sortField]==b[sortField])return(0);else return(a[sortField]<b[sortField])?-1:+1;
}
if (!co.chkSearchTitlesFirst || co.chkSearchByDate) results.sort(bySortField);
return results;
}
//}}}
// // HIJACK core {{{<<search>>}}} macro to add "report" and "simple inline" output
//{{{
config.macros.search.SOP_handler=config.macros.search.handler;
config.macros.search.handler = function(place,macroName,params)
{
// if "report", use SearchOptionsPlugin report generator for inline output
if (params[1]&¶ms[1].substr(0,6)=="report") {
var keyword=params[0];
var options=params[1].split("=")[1]; // split "report=option+option+..."
var heading=params[2]?params[2].unescapeLineBreaks():"";
var matches=store.search(new RegExp(keyword.escapeRegExp(),"img"),"title","excludeSearch");
if (matches.length) wikify(heading+window.formatSearchResults(keyword,matches,options),place);
} else if (params[1]) {
var keyword=params[0];
var heading=params[1]?params[1].unescapeLineBreaks():"";
var seperator=params[2]?params[2].unescapeLineBreaks():", ";
var matches=store.search(new RegExp(keyword.escapeRegExp(),"img"),"title","excludeSearch");
if (matches.length) {
var out=[];
for (var m=0; m<matches.length; m++) out.push("[["+matches[m].title+"]]");
wikify(heading+out.join(seperator),place);
}
} else
config.macros.search.SOP_handler.apply(this,arguments);
};
//}}}
// // SearchResults panel handling
//{{{
setStylesheet(".searchResults { padding:1em 1em 0 1em; }","searchResults"); // matches std tiddler padding
config.macros.search.createPanel=function(text,matches,body) {
function getByClass(e,c) { var d=e.getElementsByTagName("div");
for (var i=0;i<d.length;i++) if (hasClass(d[i],c)) return d[i]; }
var panel=createTiddlyElement(null,"div","searchPanel","searchPanel");
this.renderPanel(panel,text,matches,body);
var oldpanel=document.getElementById("searchPanel");
if (!oldpanel) { // insert new panel just above tiddlers
var da=document.getElementById("displayArea");
da.insertBefore(panel,da.firstChild);
} else { // if panel exists
var oldwrap=getByClass(oldpanel,"searchResults");
var newwrap=getByClass(panel,"searchResults");
// if no prior content, just insert new content
if (!oldwrap) oldpanel.insertBefore(newwrap,null);
else { // swap search results content but leave containing panel intact
oldwrap.style.display='block'; // unfold wrapper if needed
var i=oldwrap.getElementsByTagName("input")[0]; // get input field
if (i) { var pos=this.getCursorPos(i); i.onblur=null; } // get cursor pos, ignore blur
oldpanel.replaceChild(newwrap,oldwrap);
panel=oldpanel; // use existing panel
}
}
this.showPanel(true,pos);
return panel;
}
config.macros.search.renderPanel=function(panel,text,matches,body) {
var wrap=createTiddlyElement(panel,"div",null,"searchResults");
wrap.onmouseover = function(e){ addClass(this,"selected"); }
wrap.onmouseout = function(e){ removeClass(this,"selected"); }
// create toolbar: "open all", "fold/unfold", "close"
var tb=createTiddlyElement(wrap,"div",null,"toolbar");
var b=createTiddlyButton(tb, "open all", "open all matching tiddlers", function() {
story.displayTiddlers(null,this.getAttribute("list").readBracketedList()); return false; },"button");
var list=""; for(var t=0;t<matches.length;t++) list+='[['+matches[t].title+']] ';
b.setAttribute("list",list);
var b=createTiddlyButton(tb, "fold", "toggle display of search results", function() {
config.macros.search.foldPanel(this); return false; },"button");
var b=createTiddlyButton(tb, "close", "dismiss search results", function() {
config.macros.search.showPanel(false); return false; },"button");
createTiddlyText(createTiddlyElement(wrap,"div",null,"title"),"Search for: "+text); // title
wikify(body,createTiddlyElement(wrap,"div",null,"viewer")); // report
return panel;
}
config.macros.search.showPanel=function(show,pos) {
var panel=document.getElementById("searchPanel");
var i=panel.getElementsByTagName("input")[0];
i.onfocus=show?function(){config.macros.search.stayFocused(true);}:null;
i.onblur=show?function(){config.macros.search.stayFocused(false);}:null;
if (show && panel.style.display=="block") { // if shown, grab focus, restore cursor
if (i&&this.stayFocused()) { i.focus(); this.setCursorPos(i,pos); }
return;
}
if(!config.options.chkAnimate) {
panel.style.display=show?"block":"none";
if (!show) { removeChildren(panel); config.macros.search.stayFocused(false); }
} else {
var s=new Slider(panel,show,false,show?"none":"children");
s.callback=function(e,p){e.style.overflow="visible";}
anim.startAnimating(s);
}
return panel;
}
config.macros.search.foldPanel=function(button) {
var d=document.getElementById("searchPanel").getElementsByTagName("div");
for (var i=0;i<d.length;i++) if (hasClass(d[i],"viewer")) var v=d[i]; if (!v) return;
var show=v.style.display=="none";
if(!config.options.chkAnimate)
v.style.display=show?"block":"none";
else {
var s=new Slider(v,show,false,"none");
s.callback=function(e,p){e.style.overflow="visible";}
anim.startAnimating(s);
}
button.innerHTML=show?"fold":"unfold";
return false;
}
config.macros.search.stayFocused=function(keep) { // TRUE/FALSE=set value, no args=get value
if (keep===undefined) return this.keepReportInFocus;
this.keepReportInFocus=keep;
return keep
}
config.macros.search.getCursorPos=function(i) {
var s=0; var e=0; if (!i) return { start:s, end:e };
try {
if (i.setSelectionRange) // FF
{ s=i.selectionStart; e=i.selectionEnd; }
if (document.selection && document.selection.createRange) { // IE
var r=document.selection.createRange().duplicate();
var len=r.text.length; s=0-r.moveStart('character',-100000); e=s+len;
}
}catch(e){};
return { start:s, end:e };
}
config.macros.search.setCursorPos=function(i,pos) {
if (!i||!pos) return; var s=pos.start; var e=pos.end;
if (i.setSelectionRange) //FF
i.setSelectionRange(s,e);
if (i.createTextRange) // IE
{ var r=i.createTextRange(); r.collapse(true); r.moveStart("character",s); r.select(); }
}
//}}}
// // SearchResults report generation
// note: these functions are defined globally, so they can be more easily redefined to customize report formats//
//{{{
if (!window.reportSearchResults) window.reportSearchResults=function(text,matches)
{
var cms=config.macros.search; // abbrev
var body=window.formatSearchResults(text,matches);
if (!config.options.chkSearchListTiddler) // show #searchResults panel
window.scrollTo(0,ensureVisible(cms.createPanel(text,matches,body)));
else { // write [[SearchResults]] tiddler
var title=cms.reportTitle;
var who=config.options.txtUserName;
var when=new Date();
var tags="excludeLists excludeSearch temporary";
var tid=store.getTiddler(title); if (!tid) tid=new Tiddler();
tid.set(title,body,who,when,tags);
store.addTiddler(tid);
story.closeTiddler(title);
story.displayTiddler(null,title);
}
}
if (!window.formatSearchResults) window.formatSearchResults=function(text,matches,opt)
{
var body='';
var title=config.macros.search.reportTitle
var q = config.options.chkRegExpSearch ? "/" : "'";
if (!opt) var opt="all";
var parts=opt.split("+");
for (var i=0; i<parts.length; i++) { var p=parts[i].toLowerCase();
if (p=="again"||p=="all") body+=window.formatSearchResults_again(text,matches);
if (p=="summary"||p=="all") body+=window.formatSearchResults_summary(text,matches);
if (p=="list"||p=="all") body+=window.formatSearchResults_list(text,matches);
if (p=="buttons"||p=="all") body+=window.formatSearchResults_buttons(text,matches);
}
return body;
}
if (!window.formatSearchResults_again) window.formatSearchResults_again=function(text,matches)
{
var title=config.macros.search.reportTitle
var body='';
// search again
body+='{{span{<<search "'+text.replace(/"/g,'"')+'">> /%\n';
body+='%/<html><input type="button" value="search again"';
body+=' onclick="var t=this.parentNode.parentNode.getElementsByTagName(\'input\')[0];';
body+=' config.macros.search.doSearch(t); return false;">';
if (!config.options.chkSearchResultsOptions) // omit "options..."
body+='</html>';
else {
body+=' <a href="javascript:;" onclick="';
body+=' var e=this.parentNode.nextSibling;';
body+=' var show=e.style.display!=\'block\';';
body+=' if(!config.options.chkAnimate) e.style.display=show?\'block\':\'none\';';
body+=' else anim.startAnimating(new Slider(e,show,false,\'none\'));';
body+=' return false;">options...</a>';
body+='</html>@@display:none;border-left:1px dotted;margin-left:1em;padding:0;padding-left:.5em;font-size:90%;/%\n';
body+=' %/<<tiddler SearchOptions>>@@';
};
body+='}}}\n\n';
return body;
}
if (!window.formatSearchResults_summary) window.formatSearchResults_summary=function(text,matches)
{
// summary: nn tiddlers found matching '...', options used
var body='';
var co=config.options; // abbrev
var title=config.macros.search.reportTitle
var q = co.chkRegExpSearch ? "/" : "'";
body+="''"+config.macros.search.successMsg.format([matches.length,q+"{{{"+text+"}}}"+q])+"''\n";
var opts=[];
if (co.chkSearchTitles) opts.push("titles");
if (co.chkSearchText) opts.push("text");
if (co.chkSearchTags) opts.push("tags");
if (co.chkSearchFields) opts.push("fields");
if (co.chkSearchShadows) opts.push("shadows");
if (co.chkSearchOpenTiddlers) body+="^^//search limited to displayed tiddlers only//^^\n";
body+="~~ searched in "+opts.join(" + ")+"~~\n";
body+=(co.chkCaseSensitiveSearch||co.chkRegExpSearch?"^^ using ":"")
+(co.chkCaseSensitiveSearch?"case-sensitive ":"")
+(co.chkRegExpSearch?"pattern ":"")
+(co.chkCaseSensitiveSearch||co.chkRegExpSearch?"matching^^\n":"");
return body;
}
if (!window.formatSearchResults_list) window.formatSearchResults_list=function(text,matches)
{
// bullet list of links to matching tiddlers
var body='';
var co=config.options; // abbrev
var pattern=co.chkRegExpSearch?text:text.escapeRegExp();
var sensitive=co.chkCaseSensitiveSearch?"mg":"img";
var link='{{tiddlyLinkExisting{<html><nowiki><a href="javascript:;" onclick="'
+'if(config.options.chkSearchHighlight)'
+' highlightHack=new RegExp(\x27'+pattern+'\x27.escapeRegExp(),\x27'+sensitive+'\x27);'
+'story.displayTiddler(null,\x27%0\x27);'
+'highlightHack = null; return false;'
+'" title="%2">%1</a></html>}}}';
for(var t=0;t<matches.length;t++) {
body+="* ";
if (co.chkSearchByDate)
body+=matches[t].modified.formatString('YYYY.0MM.0DD 0hh:0mm')+" ";
var title=matches[t].title;
var fixup=title.replace(/'/g,"\\x27").replace(/"/g,"\\x22");
var tid=store.getTiddler(title);
var tip=tid?tid.getSubtitle():''; tip=tip.replace(/"/g,""");
body+=link.format([fixup,title,tip])+'\n';
}
return body;
}
if (!window.formatSearchResults_buttons) window.formatSearchResults_buttons=function(text,matches)
{
// embed buttons only if writing SearchResults to tiddler
if (!config.options.chkSearchListTiddler) return "";
// "open all" button
var title=config.macros.search.reportTitle;
var body="";
body+="@@diplay:block;<html><input type=\"button\" href=\"javascript:;\" "
+"onclick=\"story.displayTiddlers(null,[";
for(var t=0;t<matches.length;t++)
body+="'"+matches[t].title.replace(/\'/mg,"\\'")+"'"+((t<matches.length-1)?", ":"");
body+="],1);\" accesskey=\"O\" value=\"open all matching tiddlers\"></html> ";
// "discard SearchResults" button
body+="<html><input type=\"button\" href=\"javascript:;\" "
+"onclick=\"discardSearchResults()\" value=\"discard "+title+"\"></html>";
body+="@@\n";
return body;
}
if (!window.discardSearchResults) window.discardSearchResults=function()
{
// remove the tiddler
story.closeTiddler(config.macros.search.reportTitle);
store.deleteTiddler(config.macros.search.reportTitle);
store.notify(config.macros.search.reportTitle,true);
}
//}}}
// // DELIVER [[SearchOptions]] shadow payload
//{{{
config.shadowTiddlers.SearchOptions = store.getTiddlerText('SearchOptionsPlugin##panel','');
config.annotations.SearchOptions = 'created by SearchOptionsPlugin';
//}}}
/***
//{{{
!panel
search in:
{{nowrap{<<option chkSearchTitles>>titles <<option chkSearchText>>text <<option chkSearchTags>>tags}}} /%
%/{{nowrap{<<option chkSearchFields>>fields <<option chkSearchShadows>>shadows}}}
----
{{nowrap{<<option chkCaseSensitiveSearch>>case-sensitive}}} /%
%/{{nowrap{<<option chkRegExpSearch>>match text patterns}}}
{{nowrap{<<option chkIncrementalSearch>>key-by-key search:}}} /%
%/{{threechar smallform nowrap{<<option txtIncrementalSearchMin>> or more characters}}} /%
%/{{threechar smallform nowrap{<<option txtIncrementalSearchDelay>> msec delay}}}<hr>
{{nowrap{<<option chkSearchList>>show results in a list}}} /%
%/{{nowrap{<<option chkSearchTitlesFirst>>show title matches first}}}
{{nowrap{<<option chkSearchByDate>>sort results by date}}} /%
%/{{nowrap{<<option chkSearchHighlight>>highlight matching text}}}
----
{{nowrap{<<option chkSearchOpenTiddlers>>search open tiddlers only}}}
{{nowrap{<<option chkSearchExcludeTags>>exclude tiddlers tagged with:}}}
{{editor{<<option txtSearchExcludeTags>>}}}
!end
//}}}
***/
von Andreas Straka, 2011-2015
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','Background')}} Background $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','Foreground')}} Foreground $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','PrimaryPale')}} PrimaryPale $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','PrimaryLight')}} PrimaryLight $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','PrimaryMid')}} PrimaryMid $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','PrimaryDark')}} PrimaryDark $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','SecondaryPale')}} SecondaryPale $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','SecondaryLight')}} SecondaryLight $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','SecondaryMid')}} SecondaryMid $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','SecondaryDark')}} SecondaryDark $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','TertiaryPale')}} TertiaryPale $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','TertiaryLight')}} TertiaryLight $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','TertiaryMid')}} TertiaryMid $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','TertiaryDark')}} TertiaryDark $1>>
<<tiddler [[TemplateShowColor]] with:{{store.getTiddlerSlice('$1','Error')}} Error $1>>
@@margin:0 1em;padding:0 4em;background-color:$1; @@ @@padding-right:1em;{{{$1}}}@@ [[$2|$3]]
/***
Description: Contains the stuff you need to use Tiddlyspot
Note, you also need UploadPlugin, PasswordOptionPlugin and LoadRemoteFileThroughProxy
from http://tiddlywiki.bidix.info for a complete working Tiddlyspot site.
***/
//{{{
// edit this if you are migrating sites or retrofitting an existing TW
config.tiddlyspotSiteId = 'andreas.straka.bash';
// make it so you can by default see edit controls via http
config.options.chkHttpReadOnly = false;
window.readOnly = false; // make sure of it (for tw 2.2)
window.showBackstage = true; // show backstage too
// disable autosave in d3
if (window.location.protocol != "file:")
config.options.chkGTDLazyAutoSave = false;
// tweak shadow tiddlers to add upload button, password entry box etc
with (config.shadowTiddlers) {
SiteUrl = 'http://'+config.tiddlyspotSiteId+'.tiddlyspot.com';
SideBarOptions = SideBarOptions.replace(/(<<saveChanges>>)/,"$1<<tiddler TspotSidebar>>");
OptionsPanel = OptionsPanel.replace(/^/,"<<tiddler TspotOptions>>");
DefaultTiddlers = DefaultTiddlers.replace(/^/,"[[WelcomeToTiddlyspot]] ");
MainMenu = MainMenu.replace(/^/,"[[WelcomeToTiddlyspot]] ");
}
// create some shadow tiddler content
merge(config.shadowTiddlers,{
'TspotOptions':[
"tiddlyspot password:",
"<<option pasUploadPassword>>",
""
].join("\n"),
'TspotControls':[
"| tiddlyspot password:|<<option pasUploadPassword>>|",
"| site management:|<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . . " + config.tiddlyspotSiteId + ">>//(requires tiddlyspot password)//<br>[[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]], [[download (go offline)|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download]]|",
"| links:|[[tiddlyspot.com|http://tiddlyspot.com/]], [[FAQs|http://faq.tiddlyspot.com/]], [[blog|http://tiddlyspot.blogspot.com/]], email [[support|mailto:support@tiddlyspot.com]] & [[feedback|mailto:feedback@tiddlyspot.com]], [[donate|http://tiddlyspot.com/?page=donate]]|"
].join("\n"),
'WelcomeToTiddlyspot':[
"This document is a ~TiddlyWiki from tiddlyspot.com. A ~TiddlyWiki is an electronic notebook that is great for managing todo lists, personal information, and all sorts of things.",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //What now?// @@ Before you can save any changes, you need to enter your password in the form below. Then configure privacy and other site settings at your [[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]] (your control panel username is //" + config.tiddlyspotSiteId + "//).",
"<<tiddler TspotControls>>",
"See also GettingStarted.",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //Working online// @@ You can edit this ~TiddlyWiki right now, and save your changes using the \"save to web\" button in the column on the right.",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //Working offline// @@ A fully functioning copy of this ~TiddlyWiki can be saved onto your hard drive or USB stick. You can make changes and save them locally without being connected to the Internet. When you're ready to sync up again, just click \"upload\" and your ~TiddlyWiki will be saved back to tiddlyspot.com.",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //Help!// @@ Find out more about ~TiddlyWiki at [[TiddlyWiki.com|http://tiddlywiki.com]]. Also visit [[TiddlyWiki.org|http://tiddlywiki.org]] for documentation on learning and using ~TiddlyWiki. New users are especially welcome on the [[TiddlyWiki mailing list|http://groups.google.com/group/TiddlyWiki]], which is an excellent place to ask questions and get help. If you have a tiddlyspot related problem email [[tiddlyspot support|mailto:support@tiddlyspot.com]].",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //Enjoy :)// @@ We hope you like using your tiddlyspot.com site. Please email [[feedback@tiddlyspot.com|mailto:feedback@tiddlyspot.com]] with any comments or suggestions."
].join("\n"),
'TspotSidebar':[
"<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . . " + config.tiddlyspotSiteId + ">><html><a href='http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download' class='button'>download</a></html>"
].join("\n")
});
//}}}
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 30/01/2015 08:37:20 | Andreas | [[/|http://andreas.straka.bash.tiddlyspot.com/]] | [[store.cgi|http://andreas.straka.bash.tiddlyspot.com/store.cgi]] | . | [[index.html | http://andreas.straka.bash.tiddlyspot.com/index.html]] | . |
| 30/01/2015 08:42:41 | Andreas | [[/|http://andreas.straka.bash.tiddlyspot.com/]] | [[store.cgi|http://andreas.straka.bash.tiddlyspot.com/store.cgi]] | . | [[index.html | http://andreas.straka.bash.tiddlyspot.com/index.html]] | . |
| 13/05/2015 11:09:33 | Andreas | [[/|http://andreas.straka.bash.tiddlyspot.com/]] | [[store.cgi|http://andreas.straka.bash.tiddlyspot.com/store.cgi]] | . | [[index.html | http://andreas.straka.bash.tiddlyspot.com/index.html]] | . |
| 05/11/2015 13:12:09 | Andreas | [[/|http://andreas.straka.bash.tiddlyspot.com/]] | [[store.cgi|http://andreas.straka.bash.tiddlyspot.com/store.cgi]] | . | [[index.html | http://andreas.straka.bash.tiddlyspot.com/index.html]] | . |
| 23/11/2015 12:22:10 | Andreas | [[/|http://andreas.straka.bash.tiddlyspot.com/]] | [[store.cgi|http://andreas.straka.bash.tiddlyspot.com/store.cgi]] | . | [[index.html | http://andreas.straka.bash.tiddlyspot.com/index.html]] | . | ok |
| 23/11/2015 12:22:31 | Andreas | [[/|http://andreas.straka.bash.tiddlyspot.com/]] | [[store.cgi|http://andreas.straka.bash.tiddlyspot.com/store.cgi]] | . | [[index.html | http://andreas.straka.bash.tiddlyspot.com/index.html]] | . |
| 29/04/2016 22:09:19 | YourName | [[/|http://andreas.straka.bash.tiddlyspot.com/]] | [[store.cgi|http://andreas.straka.bash.tiddlyspot.com/store.cgi]] | . | [[index.html | http://andreas.straka.bash.tiddlyspot.com/index.html]] | . | ok |
| 29/04/2016 22:10:59 | YourName | [[/|http://andreas.straka.bash.tiddlyspot.com/]] | [[store.cgi|http://andreas.straka.bash.tiddlyspot.com/store.cgi]] | . | [[index.html | http://andreas.straka.bash.tiddlyspot.com/index.html]] | . |
| 23/05/2019 10:24:46 | YourName | [[/|http://andreas.straka.bash.tiddlyspot.com/]] | [[store.cgi|http://andreas.straka.bash.tiddlyspot.com/store.cgi]] | . | [[index.html | http://andreas.straka.bash.tiddlyspot.com/index.html]] | . |
| 25/07/2019 08:09:04 | Andreas | [[/|http://andreas.straka.bash.tiddlyspot.com/]] | [[store.cgi|http://andreas.straka.bash.tiddlyspot.com/store.cgi]] | . | [[index.html | http://andreas.straka.bash.tiddlyspot.com/index.html]] | . |
/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.3|
|''Date:''|Feb 24, 2008|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#UploadPluginDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
major: 4, minor: 1, revision: 3,
date: new Date("Feb 24, 2008"),
source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
author: 'BidiX (BidiX (at) bidix (dot) info',
coreVersion: '2.2.0'
};
//
// Environment
//
if (!window.bidix) window.bidix = {}; // bidix namespace
bidix.debugMode = false; // true to activate both in Plugin and UploadService
//
// Upload Macro
//
config.macros.upload = {
// default values
defaultBackupDir: '', //no backup
defaultStoreScript: "store.php",
defaultToFilename: "index.html",
defaultUploadDir: ".",
authenticateUser: true // UploadService Authenticate User
};
config.macros.upload.label = {
promptOption: "Save and Upload this TiddlyWiki with UploadOptions",
promptParamMacro: "Save and Upload this TiddlyWiki in %0",
saveLabel: "save to web",
saveToDisk: "save to disk",
uploadLabel: "upload"
};
config.macros.upload.messages = {
noStoreUrl: "No store URL in parmeters or options",
usernameOrPasswordMissing: "Username or password missing"
};
config.macros.upload.handler = function(place,macroName,params) {
if (readOnly)
return;
var label;
if (document.location.toString().substr(0,4) == "http")
label = this.label.saveLabel;
else
label = this.label.uploadLabel;
var prompt;
if (params[0]) {
prompt = this.label.promptParamMacro.toString().format([this.destFile(params[0],
(params[1] ? params[1]:bidix.basename(window.location.toString())), params[3])]);
} else {
prompt = this.label.promptOption;
}
createTiddlyButton(place, label, prompt, function() {config.macros.upload.action(params);}, null, null, this.accessKey);
};
config.macros.upload.action = function(params)
{
// for missing macro parameter set value from options
if (!params) params = {};
var storeUrl = params[0] ? params[0] : config.options.txtUploadStoreUrl;
var toFilename = params[1] ? params[1] : config.options.txtUploadFilename;
var backupDir = params[2] ? params[2] : config.options.txtUploadBackupDir;
var uploadDir = params[3] ? params[3] : config.options.txtUploadDir;
var username = params[4] ? params[4] : config.options.txtUploadUserName;
var password = config.options.pasUploadPassword; // for security reason no password as macro parameter
// for still missing parameter set default value
if ((!storeUrl) && (document.location.toString().substr(0,4) == "http"))
storeUrl = bidix.dirname(document.location.toString())+'/'+config.macros.upload.defaultStoreScript;
if (storeUrl.substr(0,4) != "http")
storeUrl = bidix.dirname(document.location.toString()) +'/'+ storeUrl;
if (!toFilename)
toFilename = bidix.basename(window.location.toString());
if (!toFilename)
toFilename = config.macros.upload.defaultToFilename;
if (!uploadDir)
uploadDir = config.macros.upload.defaultUploadDir;
if (!backupDir)
backupDir = config.macros.upload.defaultBackupDir;
// report error if still missing
if (!storeUrl) {
alert(config.macros.upload.messages.noStoreUrl);
clearMessage();
return false;
}
if (config.macros.upload.authenticateUser && (!username || !password)) {
alert(config.macros.upload.messages.usernameOrPasswordMissing);
clearMessage();
return false;
}
bidix.upload.uploadChanges(false,null,storeUrl, toFilename, uploadDir, backupDir, username, password);
return false;
};
config.macros.upload.destFile = function(storeUrl, toFilename, uploadDir)
{
if (!storeUrl)
return null;
var dest = bidix.dirname(storeUrl);
if (uploadDir && uploadDir != '.')
dest = dest + '/' + uploadDir;
dest = dest + '/' + toFilename;
return dest;
};
//
// uploadOptions Macro
//
config.macros.uploadOptions = {
handler: function(place,macroName,params) {
var wizard = new Wizard();
wizard.createWizard(place,this.wizardTitle);
wizard.addStep(this.step1Title,this.step1Html);
var markList = wizard.getElement("markList");
var listWrapper = document.createElement("div");
markList.parentNode.insertBefore(listWrapper,markList);
wizard.setValue("listWrapper",listWrapper);
this.refreshOptions(listWrapper,false);
var uploadCaption;
if (document.location.toString().substr(0,4) == "http")
uploadCaption = config.macros.upload.label.saveLabel;
else
uploadCaption = config.macros.upload.label.uploadLabel;
wizard.setButtons([
{caption: uploadCaption, tooltip: config.macros.upload.label.promptOption,
onClick: config.macros.upload.action},
{caption: this.cancelButton, tooltip: this.cancelButtonPrompt, onClick: this.onCancel}
]);
},
options: [
"txtUploadUserName",
"pasUploadPassword",
"txtUploadStoreUrl",
"txtUploadDir",
"txtUploadFilename",
"txtUploadBackupDir",
"chkUploadLog",
"txtUploadLogMaxLine"
],
refreshOptions: function(listWrapper) {
var opts = [];
for(i=0; i<this.options.length; i++) {
var opt = {};
opts.push();
opt.option = "";
n = this.options[i];
opt.name = n;
opt.lowlight = !config.optionsDesc[n];
opt.description = opt.lowlight ? this.unknownDescription : config.optionsDesc[n];
opts.push(opt);
}
var listview = ListView.create(listWrapper,opts,this.listViewTemplate);
for(n=0; n<opts.length; n++) {
var type = opts[n].name.substr(0,3);
var h = config.macros.option.types[type];
if (h && h.create) {
h.create(opts[n].colElements['option'],type,opts[n].name,opts[n].name,"no");
}
}
},
onCancel: function(e)
{
backstage.switchTab(null);
return false;
},
wizardTitle: "Upload with options",
step1Title: "These options are saved in cookies in your browser",
step1Html: "<input type='hidden' name='markList'></input><br>",
cancelButton: "Cancel",
cancelButtonPrompt: "Cancel prompt",
listViewTemplate: {
columns: [
{name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
{name: 'Option', field: 'option', title: "Option", type: 'String'},
{name: 'Name', field: 'name', title: "Name", type: 'String'}
],
rowClasses: [
{className: 'lowlight', field: 'lowlight'}
]}
};
//
// upload functions
//
if (!bidix.upload) bidix.upload = {};
if (!bidix.upload.messages) bidix.upload.messages = {
//from saving
invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
backupSaved: "Backup saved",
backupFailed: "Failed to upload backup file",
rssSaved: "RSS feed uploaded",
rssFailed: "Failed to upload RSS feed file",
emptySaved: "Empty template uploaded",
emptyFailed: "Failed to upload empty template file",
mainSaved: "Main TiddlyWiki file uploaded",
mainFailed: "Failed to upload main TiddlyWiki file. Your changes have not been saved",
//specific upload
loadOriginalHttpPostError: "Can't get original file",
aboutToSaveOnHttpPost: 'About to upload on %0 ...',
storePhpNotFound: "The store script '%0' was not found."
};
bidix.upload.uploadChanges = function(onlyIfDirty,tiddlers,storeUrl,toFilename,uploadDir,backupDir,username,password)
{
var callback = function(status,uploadParams,original,url,xhr) {
if (!status) {
displayMessage(bidix.upload.messages.loadOriginalHttpPostError);
return;
}
if (bidix.debugMode)
alert(original.substr(0,500)+"\n...");
// Locate the storeArea div's
var posDiv = locateStoreArea(original);
if((posDiv[0] == -1) || (posDiv[1] == -1)) {
alert(config.messages.invalidFileError.format([localPath]));
return;
}
bidix.upload.uploadRss(uploadParams,original,posDiv);
};
if(onlyIfDirty && !store.isDirty())
return;
clearMessage();
// save on localdisk ?
if (document.location.toString().substr(0,4) == "file") {
var path = document.location.toString();
var localPath = getLocalPath(path);
saveChanges();
}
// get original
var uploadParams = new Array(storeUrl,toFilename,uploadDir,backupDir,username,password);
var originalPath = document.location.toString();
// If url is a directory : add index.html
if (originalPath.charAt(originalPath.length-1) == "/")
originalPath = originalPath + "index.html";
var dest = config.macros.upload.destFile(storeUrl,toFilename,uploadDir);
var log = new bidix.UploadLog();
log.startUpload(storeUrl, dest, uploadDir, backupDir);
displayMessage(bidix.upload.messages.aboutToSaveOnHttpPost.format([dest]));
if (bidix.debugMode)
alert("about to execute Http - GET on "+originalPath);
var r = doHttp("GET",originalPath,null,null,username,password,callback,uploadParams,null);
if (typeof r == "string")
displayMessage(r);
return r;
};
bidix.upload.uploadRss = function(uploadParams,original,posDiv)
{
var callback = function(status,params,responseText,url,xhr) {
if(status) {
var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
displayMessage(bidix.upload.messages.rssSaved,bidix.dirname(url)+'/'+destfile);
bidix.upload.uploadMain(params[0],params[1],params[2]);
} else {
displayMessage(bidix.upload.messages.rssFailed);
}
};
// do uploadRss
if(config.options.chkGenerateAnRssFeed) {
var rssPath = uploadParams[1].substr(0,uploadParams[1].lastIndexOf(".")) + ".xml";
var rssUploadParams = new Array(uploadParams[0],rssPath,uploadParams[2],'',uploadParams[4],uploadParams[5]);
var rssString = generateRss();
// no UnicodeToUTF8 conversion needed when location is "file" !!!
if (document.location.toString().substr(0,4) != "file")
rssString = convertUnicodeToUTF8(rssString);
bidix.upload.httpUpload(rssUploadParams,rssString,callback,Array(uploadParams,original,posDiv));
} else {
bidix.upload.uploadMain(uploadParams,original,posDiv);
}
};
bidix.upload.uploadMain = function(uploadParams,original,posDiv)
{
var callback = function(status,params,responseText,url,xhr) {
var log = new bidix.UploadLog();
if(status) {
// if backupDir specified
if ((params[3]) && (responseText.indexOf("backupfile:") > -1)) {
var backupfile = responseText.substring(responseText.indexOf("backupfile:")+11,responseText.indexOf("\n", responseText.indexOf("backupfile:")));
displayMessage(bidix.upload.messages.backupSaved,bidix.dirname(url)+'/'+backupfile);
}
var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
displayMessage(bidix.upload.messages.mainSaved,bidix.dirname(url)+'/'+destfile);
store.setDirty(false);
log.endUpload("ok");
} else {
alert(bidix.upload.messages.mainFailed);
displayMessage(bidix.upload.messages.mainFailed);
log.endUpload("failed");
}
};
// do uploadMain
var revised = bidix.upload.updateOriginal(original,posDiv);
bidix.upload.httpUpload(uploadParams,revised,callback,uploadParams);
};
bidix.upload.httpUpload = function(uploadParams,data,callback,params)
{
var localCallback = function(status,params,responseText,url,xhr) {
url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
if (xhr.status == 404)
alert(bidix.upload.messages.storePhpNotFound.format([url]));
if ((bidix.debugMode) || (responseText.indexOf("Debug mode") >= 0 )) {
alert(responseText);
if (responseText.indexOf("Debug mode") >= 0 )
responseText = responseText.substring(responseText.indexOf("\n\n")+2);
} else if (responseText.charAt(0) != '0')
alert(responseText);
if (responseText.charAt(0) != '0')
status = null;
callback(status,params,responseText,url,xhr);
};
// do httpUpload
var boundary = "---------------------------"+"AaB03x";
var uploadFormName = "UploadPlugin";
// compose headers data
var sheader = "";
sheader += "--" + boundary + "\r\nContent-disposition: form-data; name=\"";
sheader += uploadFormName +"\"\r\n\r\n";
sheader += "backupDir="+uploadParams[3] +
";user=" + uploadParams[4] +
";password=" + uploadParams[5] +
";uploaddir=" + uploadParams[2];
if (bidix.debugMode)
sheader += ";debug=1";
sheader += ";;\r\n";
sheader += "\r\n" + "--" + boundary + "\r\n";
sheader += "Content-disposition: form-data; name=\"userfile\"; filename=\""+uploadParams[1]+"\"\r\n";
sheader += "Content-Type: text/html;charset=UTF-8" + "\r\n";
sheader += "Content-Length: " + data.length + "\r\n\r\n";
// compose trailer data
var strailer = new String();
strailer = "\r\n--" + boundary + "--\r\n";
data = sheader + data + strailer;
if (bidix.debugMode) alert("about to execute Http - POST on "+uploadParams[0]+"\n with \n"+data.substr(0,500)+ " ... ");
var r = doHttp("POST",uploadParams[0],data,"multipart/form-data; ;charset=UTF-8; boundary="+boundary,uploadParams[4],uploadParams[5],localCallback,params,null);
if (typeof r == "string")
displayMessage(r);
return r;
};
// same as Saving's updateOriginal but without convertUnicodeToUTF8 calls
bidix.upload.updateOriginal = function(original, posDiv)
{
if (!posDiv)
posDiv = locateStoreArea(original);
if((posDiv[0] == -1) || (posDiv[1] == -1)) {
alert(config.messages.invalidFileError.format([localPath]));
return;
}
var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" +
store.allTiddlersAsHtml() + "\n" +
original.substr(posDiv[1]);
var newSiteTitle = getPageTitle().htmlEncode();
revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead");
revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead");
revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody");
revised = updateMarkupBlock(revised,"POST-SCRIPT","MarkupPostBody");
return revised;
};
//
// UploadLog
//
// config.options.chkUploadLog :
// false : no logging
// true : logging
// config.options.txtUploadLogMaxLine :
// -1 : no limit
// 0 : no Log lines but UploadLog is still in place
// n : the last n lines are only kept
// NaN : no limit (-1)
bidix.UploadLog = function() {
if (!config.options.chkUploadLog)
return; // this.tiddler = null
this.tiddler = store.getTiddler("UploadLog");
if (!this.tiddler) {
this.tiddler = new Tiddler();
this.tiddler.title = "UploadLog";
this.tiddler.text = "| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |";
this.tiddler.created = new Date();
this.tiddler.modifier = config.options.txtUserName;
this.tiddler.modified = new Date();
store.addTiddler(this.tiddler);
}
return this;
};
bidix.UploadLog.prototype.addText = function(text) {
if (!this.tiddler)
return;
// retrieve maxLine when we need it
var maxLine = parseInt(config.options.txtUploadLogMaxLine,10);
if (isNaN(maxLine))
maxLine = -1;
// add text
if (maxLine != 0)
this.tiddler.text = this.tiddler.text + text;
// Trunck to maxLine
if (maxLine >= 0) {
var textArray = this.tiddler.text.split('\n');
if (textArray.length > maxLine + 1)
textArray.splice(1,textArray.length-1-maxLine);
this.tiddler.text = textArray.join('\n');
}
// update tiddler fields
this.tiddler.modifier = config.options.txtUserName;
this.tiddler.modified = new Date();
store.addTiddler(this.tiddler);
// refresh and notifiy for immediate update
story.refreshTiddler(this.tiddler.title);
store.notify(this.tiddler.title, true);
};
bidix.UploadLog.prototype.startUpload = function(storeUrl, toFilename, uploadDir, backupDir) {
if (!this.tiddler)
return;
var now = new Date();
var text = "\n| ";
var filename = bidix.basename(document.location.toString());
if (!filename) filename = '/';
text += now.formatString("0DD/0MM/YYYY 0hh:0mm:0ss") +" | ";
text += config.options.txtUserName + " | ";
text += "[["+filename+"|"+location + "]] |";
text += " [[" + bidix.basename(storeUrl) + "|" + storeUrl + "]] | ";
text += uploadDir + " | ";
text += "[[" + bidix.basename(toFilename) + " | " +toFilename + "]] | ";
text += backupDir + " |";
this.addText(text);
};
bidix.UploadLog.prototype.endUpload = function(status) {
if (!this.tiddler)
return;
this.addText(" "+status+" |");
};
//
// Utilities
//
bidix.checkPlugin = function(plugin, major, minor, revision) {
var ext = version.extensions[plugin];
if (!
(ext &&
((ext.major > major) ||
((ext.major == major) && (ext.minor > minor)) ||
((ext.major == major) && (ext.minor == minor) && (ext.revision >= revision))))) {
// write error in PluginManager
if (pluginInfo)
pluginInfo.log.push("Requires " + plugin + " " + major + "." + minor + "." + revision);
eval(plugin); // generate an error : "Error: ReferenceError: xxxx is not defined"
}
};
bidix.dirname = function(filePath) {
if (!filePath)
return;
var lastpos;
if ((lastpos = filePath.lastIndexOf("/")) != -1) {
return filePath.substring(0, lastpos);
} else {
return filePath.substring(0, filePath.lastIndexOf("\\"));
}
};
bidix.basename = function(filePath) {
if (!filePath)
return;
var lastpos;
if ((lastpos = filePath.lastIndexOf("#")) != -1)
filePath = filePath.substring(0, lastpos);
if ((lastpos = filePath.lastIndexOf("/")) != -1) {
return filePath.substring(lastpos + 1);
} else
return filePath.substring(filePath.lastIndexOf("\\")+1);
};
bidix.initOption = function(name,value) {
if (!config.options[name])
config.options[name] = value;
};
//
// Initializations
//
// require PasswordOptionPlugin 1.0.1 or better
bidix.checkPlugin("PasswordOptionPlugin", 1, 0, 1);
// styleSheet
setStylesheet('.txtUploadStoreUrl, .txtUploadBackupDir, .txtUploadDir {width: 22em;}',"uploadPluginStyles");
//optionsDesc
merge(config.optionsDesc,{
txtUploadStoreUrl: "Url of the UploadService script (default: store.php)",
txtUploadFilename: "Filename of the uploaded file (default: in index.html)",
txtUploadDir: "Relative Directory where to store the file (default: . (downloadService directory))",
txtUploadBackupDir: "Relative Directory where to backup the file. If empty no backup. (default: ''(empty))",
txtUploadUserName: "Upload Username",
pasUploadPassword: "Upload Password",
chkUploadLog: "do Logging in UploadLog (default: true)",
txtUploadLogMaxLine: "Maximum of lines in UploadLog (default: 10)"
});
// Options Initializations
bidix.initOption('txtUploadStoreUrl','');
bidix.initOption('txtUploadFilename','');
bidix.initOption('txtUploadDir','');
bidix.initOption('txtUploadBackupDir','');
bidix.initOption('txtUploadUserName','');
bidix.initOption('pasUploadPassword','');
bidix.initOption('chkUploadLog',true);
bidix.initOption('txtUploadLogMaxLine','10');
// Backstage
merge(config.tasks,{
uploadOptions: {text: "upload", tooltip: "Change UploadOptions and Upload", content: '<<uploadOptions>>'}
});
config.backstageTasks.push("uploadOptions");
//}}}
Einführung siehe [[Grundlagen]]
!!Arrays
{{{
a[0]="Bob Dylan"
a[1]="Bruce Springsteen"
b=(eins zwei drei vier)
dateien=(*.dat)
for i in "${a[@]}"
do
echo ${a[i]}
done
echo "Anzahl Elemente im Array: " ${#arr[@]}
unset a[1] #Element loeschen
unset a #Array loeschen
}}}
!!Assoziative Arrays / Hashes (Bash 4.1)
Deklarierung (notwendig)
{{{
declare -A Name_von_user
}}}
Initialisierung
{{{
Name_von_user[andreas]="Andreas Straka"
}}}
Werte abfragen
{{{
echo "Name von User andreas: ${Name_von_user[andreas]}
}}}
Werte iterieren mittels Schlüsselliste
{{{
for user in "${!Name_von_user[@]}"
do
echo "User $user, Name: ${Name_von_user[$user]}"
done
}}}
!!IFS ändern
|$IFS|Internal Field Separator: Zeichen, das bei bestimmten Operationen als Trennzeichen dient|
{{{
oldIFS=$IFS
IFS=":"
for dir in $PATH
do ls $dir
done
IFS=$oldIFS
}}}
!!Bash-Variablenfeatures
|<nowiki>${antwort:-keine}</nowiki>|Variable ergibt "keine" wenn sie nicht definiert ist|
|<nowiki>${antwort:=keine}</nowiki>|Variable ergibt "keine" wenn sie nicht definiert ist, und sie wird mit dem Wert "keine" definiert|
Es gibt noch einige andere Möglichkeiten, die aber mit anderen in diesem Wiki vorgestellten Befehlen besser verständlich umgesetzt werden können.
Diese Webseite enthält eine Beschreibung der wichtigsten ~Bash-Features.
Sie ist hauptsächlich dafür gedacht, diejenigen Bestandteile der bash-Programmierung schnellstmöglich verfügbar zu haben, die man ständig braucht.
Es ist keine umfassende Referenz, auch kein Tutorial, wenn auch erklärende Sätze für Neueinsteiger hinzugefügt wurden.
*Es gibt immer mehrere Wege etwas umzusetzen. Ich habe darauf geachtet dass, wenn klar ersichtlich, jeweils nur ein Weg, der meiner Meinung nach Beste, enthalten ist.
*Jeder Programmierer hat seinen eigenen Stil, und das ist mein "Best Of" der Programmiertechniken in der Bash, auf Grund meines Berufes zugeschnitten auf die Bedürfnisse eines ~FEM-Berechners.
*Mit den dargestellten "~Code-Schnipsel" kann man die meisten Probleme lösen. Bei schwierigeren Fragestellungen muss man auf eine mächtigere Programmiersprache umsteigen, z.B. Perl, oder eine umfassendere Referenz benutzen, die es ja zuhauf im Netz gibt.
*Wer schon Vorkenntnisse in der Programmierung und in der Benutzung der ~Unix-Kommandozeile hat, wird sich auch schnell mit diesem Wiki in die ~Bash-Programmierung einarbeiten können.
Viel Spass damit,
Andreas Straka
Tip für die Darstellung:
* Ctlr-+ Ctrl-'-' für Vergrößern/Verkleinern der Schrift
!Zeichenketten manipulieren
Zeichenkette ersetzen:
zeichenkette_komplett_neu=$(echo $zeichenkette_komplett_alt | sed -e "s/zeichenkette_alt/zeichenkette_neu/g")
{{{
name_neu=$(echo $name_alt | sed -e "s/alt/neu/g")
}}}
besser für einzelne Wörter oder Zeilen:
|<nowiki>${text//alt/neu}</nowiki>|Text in Variable ersetzen durch neuen Text|
Zeichenkette löschen:
{{{
sed -e "s/loeschtext//g"
}}}
zu Großbuchstaben wandeln
{{{
echo $name | tr 'a-z' 'A-Z'
}}}
fixed-field-Format einer Zeichenkette, printf-Kommando
mit dem Printf Befehl kann man die Formatierung von Zahlen und Zeichenketten steuern, siehe manpage.
{{{
printf "%-7s" "$variant_number" | sed -e "s/ /_/g"
}}}
!Zeichenketten trennen
!! ~Standard-Datentrennung
{{{
zeile="34 4.444 0.3333 2323.3"
set -- $zeile
number=$1
value1=$2
...
}}}
Das set Kommando belegt $1, .... ($@) mit den mit $IFS zerlegten Teilzeichenketten.
-- ist Optional und verhindert die Shellinterpretation von Zeichenketten in $line
!!Daten trennen mit cut und awk
Kommando cut oder awk:
{{{
data="44.3 333.2"
x=$(echo $data | cut -d' ' -f1)
y=$(echo $data | cut -d' ' -f2)
}}}
{{{
data="44.3:333.2"
x=$(echo $data | awk -F: '{print $1}')
}}}
Ausgeben der zweiten Spalte ([ \t]+ Trennzeichen) - funktioniert besser als cut bei whitespaces
{{{
cat file | awk '{print $2}'
}}}
nützlich: mehrere Leerzeichen durch eines ersetzen oder anderen Field Separator
{{{sed -e "s/\s\+/ /g"}}}
siehe man cut, awk
ZEILEN-ABSTÄNDE:
# Doppelter Zeilenvorschub
sed G
# Doppelter Zeilenabstand für Dateien, die Leerzeilen enthalten.
# Die Ausgabe sollte keine zwei aufeinander folgenden Leerzeilen enthalten.
sed '/^$/d;G'
# Dreifacher Zeilenvorschub
sed 'G;G'
# Doppelter Zeilenvorschub rückgängig machen
# (Annahme: jede zweite Zeile ist leer)
sed 'n;d'
# Füge eine Leerzeile über jeder Zeile ein, die "regex" enthält
sed '/regex/{x;p;x;}'
# Füge eine Leerzeile unter jeder Zeile ein, die "regex" enthält
sed '/regex/G'
# Füge eine Leerzeile über und unter jeder Zeile ein, die "regex" enthält
sed '/regex/{x;p;x;G;}'
Nummerierung
# Nummeriere alle Zeilen (linksbündig). Der Tabulator anstelle von Leerzeichen
# erhält den Rand. (siehe auch die Bemerkung zu '\t' am Ende dieser Datei)
sed = filename | sed 'N;s/\n/\t/'
# Nummeriere alle Zeilen (Zahl rechtsbündig in linker Spalte)
sed = filename | sed 'N; s/^/ /; s/ *\(.\{6,\}\)\n/\1 /'
# Nummeriere alle Zeilen, aber die Nummern von Leerzeilen werden nicht ausgegeben.
sed '/./=' filename | sed '/./N; s/\n/ /'
# Zeilen zählen (Nachahmung von "wc -l")
sed -n '$='
TEXT UMWANDLUNG UND ERSETZUNG:
# IN EINER UNIX UMGEBUNG: Wandle DOS Zeilenvorschübe (CR/LF) in das Unix-Format.
sed 's/.$//' # Annahme: Alle Zeilen enden mit CR/LF
sed 's/^M$//' # Bei bash/tcsh: Ctrl-V dann Ctrl-M
sed 's/\x0D$//' # für ssed, gsed 3.02.80 oder neuere Versionen
# IN EINER UNIX UMGEBUNG: Wandle Unix Zeilenvorschübe (LF) in das DOS-Format.
sed "s/$/`echo -e \\\r`/" # ksh
sed 's/$'"/`echo \\\r`/" # bash
sed "s/$/`echo \\\r`/" # zsh
sed 's/$/\r/' # gsed 3.02.80 oder neuere Versionen
# IN EINER DOS UMGEBUNG: Wandle Unix Zeilenvorschübe (LF) in das DOS-Format.
sed "s/$//" # Möglichkeit 1
sed -n p # Möglichkeit 2
# IN EINER DOS UMGEBUNG: Wandle DOS Zeilenvorschübe (CR/LF) in das Unix-Format.
# Die kann mit mit der UnxUtils Version von sed, Version 4.0.7 oder neuer
# gemacht werden. Die UnxUtils Version von sed kann durch die zusätzliche
# "--text" Option bestimmt werden, die beim Aufruf mit "--help" angezeigt wird.
# Ansonsten kann die Umwandlung von DOS-Zeilenvorschüben in UNIX-Zeilenvorschübe
# nicht mit sed unter DOS vorgenommen werden. Benutzen Sie stattdessen "tr".
sed "s/\r//" infile >outfile # UnxUtils sed v4.0.7 oder neuer
tr -d \r <infile >outfile # GNU tr Version 1.22 oder neuer
# Lösche alle Einrückungen (Leerzeichen, Tabulatoren) vom Anfang jeder Zeile
# Richtet alle Zeilen linksbündig aus.
sed 's/^[ \t]*//' # (siehe auch die Bemerkung zu '\t' am Ende dieser Datei)
# Lösche unsichtbare Zeichen (Leerzeichen, Tabulatoren) vom Ende aller Zeilen
sed 's/[ \t]*$//' # (siehe auch die Bemerkung zu '\t' am Ende dieser Datei)
# Lösche unsichtbare Zeichen sowohl am Anfang als auch am Ende jeder Zeile
sed 's/^[ \t]*//;s/[ \t]*$//'
# Füge 5 Leerzeichen am Anfang jeder Zeile ein. (Einrückung)
sed 's/^/ /'
# Alle Zeilen rechtsbündig ausrichten (Spaltenbreite: 79 Zeichen)
sed -e :a -e 's/^.\{1,78\}$/ &/;ta' # set at 78 plus 1 space
# Zentriere alle Zeilen in einer 79-Zeichen breiten Spalte.
# Bei Methode 1 bleiben Leerzeichen am Zeilenanfang und -ende erhalten.
# Bei Methode 2 werden Leerzeichen am Zeilenanfang gelöscht und es
# folgen keine Leerzeichen am Zeilenende.
sed -e :a -e 's/^.\{1,77\}$/ & /;ta' # Möglichkeit 1
sed -e :a -e 's/^.\{1,77\}$/ &/;ta' -e 's/\( *\)\1/\1/' # Möglichkeit 2
# Ersetze (Suchen und Ersetzen) "foo" mit "bar" in jeder Zeile
sed 's/foo/bar/' # Ersetzt nur das 1. Vorkommen pro Zeile
sed 's/foo/bar/4' # Ersetzt nur das 4. Vorkommen pro Zeile
sed 's/foo/bar/g' # Ersetzt ALLE Vorkommen von "foo" mit "bar"
sed 's/\(.*\)foo\(.*foo\)/\1bar\2/' # Ersetzt nur das vorletzte Vorkommen pro Zeile
sed 's/\(.*\)foo/\1bar/' # Ersetzt nur das letzte Vorkommen pro Zeile
# Ersetze "foo" mit "bar" NUR in Zeilen die "baz" enthalten
sed '/baz/s/foo/bar/g'
# Ersetze "foo" mit "bar" AUSSER in Zeilen die "baz" enthalten
sed '/baz/!s/foo/bar/g'
# Ersetze "scarlet", "ruby" oder "puce" mit "red"
sed 's/scarlet/red/g;s/ruby/red/g;s/puce/red/g' # Die meisten seds
gsed 's/scarlet\|ruby\|puce/red/g' # Nur GNU sed
# Kehre die Reihenfolge der Zeilen um (entspricht "tac")
# Bug/Feature in HHsed v1.5 löscht hierbei Leerzeilen
sed '1!G;h;$!d' # Möglichkeit 1
sed -n '1!G;h;$p' # Möglichkeit 2
# Kehre die Reihenfolge der Buchstaben innerhalb jeder Zeile um (entspricht "rev")
sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'
# Füge Zeilenpaare nebeneinander zusammen (entspricht "paste")
sed '$!N;s/\n/ /'
# Falls eine Zeile mit einem Rückwärtsstrich "\" endet, füge die nächste hinzu.
sed -e :a -e '/\\$/N; s/\\\n//; ta'
# Falls eine Zeile mit einem Gleichheitszeichen "=" beginnt,
# füge die vorhergehende hinzu und ersetzt das "=" mit einem Leerzeichen.
sed -e :a -e '$!N;s/\n=/ /;ta' -e 'P;D'
# Füge Kommas in Zahlenfolgen ein. Aus "1234567" wird "1,234,567"
gsed ':a;s/\B[0-9]\{3\}\>/,&/;ta' # GNU sed
sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta' # Andere seds
# Füge Kommas in Zahlenfolgen mit Dezimalpunkt und Vorzeichen ein. (GNU sed)
gsed -r ':a;s/(^|[^0-9.])([0-9]+)([0-9]{3})/\1\2,\3/g;ta'
# Füge alle 5 Zeilen eine Leerzeile ein. (Nach 5, 10, 15, 20,... Zeilen)
gsed '0~5G' # GNU sed
sed 'n;n;n;n;G;' # andere seds
DRUCKEN AUSGEWÄHLTER ZEILEN:
# Ausgabe der ersten 10 Zeilen einer Datei (wie "head")
sed 10q
# Ausgabe der ersten Zeilen einer Datei (wie "head -1")
sed q
# Ausgabe der letzten 10 Zeilen einer Datei (wie "tail")
sed -e :a -e '$q;N;11,$D;ba'
# Ausgabe der letzten beiden Zeilen einer Datei (wie "tail -2")
sed '$!N;$!D'
# Ausgabe der letzten Zeilen einer Datei (wie "tail -1")
sed '$!d' # Möglichkeit 1
sed -n '$p' # Möglichkeit 2
# Ausgabe der vorletzten Zeile einer Datei
sed -e '$!{h;d;}' -e x # Bei einzeiligen Dateien wird eine Leerzeile ausgegeben
sed -e '1{$q;}' -e '$!{h;d;}' -e x # Bei einzeiligen Dateien wird die Zeile ausgegeben
sed -e '1{$d;}' -e '$!{h;d;}' -e x # Bei einzeiligen Dateien wird nichts ausgegeben
# Ausgabe der Zeilen, die durch den Regulären Ausdruck (Regex) definiert sind (wie "grep")
sed -n '/regexp/p' # Möglichkeit 1
sed '/regexp/!d' # Möglichkeit 2
# Ausgabe der Zeilen, die den Reguläre Ausdruck NICHT erfüllen (wie "grep -v")
sed -n '/regexp/!p' # Möglichkeit 1, entspricht obiger Lösung
sed '/regexp/d' # Möglichkeit 2, Einfacher Syntax
# Ausgabe der Zeile direkt oberhalb des Regex, jedoch nicht die Zeile
# die den Regex erfüllt.
sed -n '/regexp/{g;1!p;};h'
# Ausgabe der Zeile direkt unterhalb des Regex, jedoch nicht die Zeile
# die den Regex erfüllt.
sed -n '/regexp/{n;p;}'
# Ausgabe eine umgebende Zeile vor und nach der Regex, mit Angabe
# der Zeilennummer der Zeile, die den Regex erfüllt. (ähnlich "grep -A1 -B1")
sed -n -e '/regexp/{=;x;1!p;g;$!N;p;D;}' -e h
# Suche nach AAA und BBB und CCC (in beliebiger Reihenfolge)
sed '/AAA/!d; /BBB/!d; /CCC/!d'
# Suche nach AAA und BBB und CCC (in vorgegebener Reihenfolge)
sed '/AAA.*BBB.*CCC/!d'
# Suche nach AAA oder BBB oder CCC (wie "egrep")
sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d # die meisten seds
gsed '/AAA\|BBB\|CCC/!d' # GNU sed
# Ausgabe des Absatzes falls dieser AAA enthält (Leerzeilen trennen Absätze)
# Für HHsed v1.5 muss 'G;' nach 'x;' eingefügt werden.
sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;'
# Ausgabe des Absatzes falls dieser AAA, BBB und CCC enthält. (Reihenfolge egal)
# Für HHsed v1.5 muss 'G;' nach 'x;' eingefügt werden.
sed -e '/./{H;$!d;}' -e 'x;/AAA/!d;/BBB/!d;/CCC/!d'
# Ausgabe des Absatzes falls dieser AAA, BBB oder CCC enthält.
# Für HHsed v1.5 muss 'G;' nach 'x;' eingefügt werden.
sed -e '/./{H;$!d;}' -e 'x;/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d
gsed '/./{H;$!d;};x;/AAA\|BBB\|CCC/b;d' # nur GNU sed
# Ausgabe der Zeilen die 65 Zeichen lang oder länger sind
sed -n '/^.\{65\}/p'
# Ausgabe der Zeilen die kürzer als 65 Zeichen sind
sed -n '/^.\{65\}/!p' # Möglichkeit 1, entspricht obiger Lösung
sed '/^.\{65\}/d' # Möglichkeit 2, eifacherer Syntax
# Ausgabe der Datei ab dem regulären Ausdruck bis zum Ende
sed -n '/regexp/,$p'
# Ausgabe eines Abschnittes der Datei, der durch Zeilennummern definiert ist
# (hier: 8-12, inklusive)
sed -n '8,12p' # Möglichkeit 1
sed '8,12!d' # Möglichkeit 2
# Ausgabe von Zeile 52
sed -n '52p' # Möglichkeit 1
sed '52!d' # Möglichkeit 2
sed '52q;d' # Möglichkeit 3, effizient für große Dateien
# Ausgabe jeder 7. Zeile - beginnend bei Zeile 3
gsed -n '3~7p' # nur GNU sed
sed -n '3,${p;n;n;n;n;n;n;}' # andere seds
# Ausgabe des Teils der Datei, der zwischen den regulären Ausdrücken ist (inklusive der Regexs)
sed -n '/Iowa/,/Montana/p' # berücksichtigt die Groß/Kleinschreibung
LÖSCHUNG BESTIMMTER ZEILEN:
# Ausgabe der Datei, AUSSER dem Teil, der zwischen den regulären Ausdrücken ist
sed '/Iowa/,/Montana/d'
# Löschung von aufeinander folgenden, identischen Zeilen (wie "uniq").
# Die erste Zeile in einer Folge von Duplikaten wird ausgegeben, der Rest gelöscht.
sed '$!N; /^\(.*\)\n\1$/!P; D'
# Lösche identische, nicht aufeinander folgende Zeilen einer Datei.
# Achten Sie darauf nicht die Buffer-größe des "Hold-spaces" zu überschreiten oder benutzen Sie GNU sed.
sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'
# Löscht alle Zeilen außer Duplikate (wie "uniq -d").
sed '$!N; s/^\(.*\)\n\1$/\1/; t; D'
# Löscht die ersten 10 Zeilen einer Datei
sed '1,10d'
# Löscht die letzte Zeile einer Datei
sed '$d'
# Löscht die zwei letzten Zeilen einer Datei
sed 'N;$!P;$!D;$d'
# Löscht die 10 letzten Zeilen einer Datei
sed -e :a -e '$d;N;2,10ba' -e 'P;D' # Möglichkeit 1
sed -n -e :a -e '1,10!{P;N;D;};N;ba' # Möglichkeit 2
# Lösche jede 8. Zeile
gsed '0~8d' # nur GNU sed
sed 'n;n;n;n;n;n;n;d;' # andere seds
# Lösche Zeilen die die Regex erfüllen
sed '/pattern/d'
# Lösche ALLE Leerzeilen aus einer Datei (wie "grep '.' ")
sed '/^$/d' # Möglichkeit 1
sed '/./!d' # Möglichkeit 2
# Lösche alle AUFEINANDER FOLGENDEN Leerzeilen außer der ersten;
# außerdem, lösche alle Leerzeilen am Anfang und am Ende der Datei
# (Wie "cat -s")
sed '/./,/^$/!d' # Möglichkeit 1, lässt 0 Leerzeilen am Anfang, 1 am Ende der Datei
sed '/^$/N;/\n$/D' # Möglichkeit 2, lässt 1 Leerzeilen am Anfang, 0 am Ende der Datei
# Lösche alle AUFEINANDER FOLGENDEN Leerzeilen, außer die ersten 2:
sed '/^$/N;/\n$/N;//D'
# Lösche alle Leerzeilen am Anfang einer Datei
sed '/./,$!d'
# Lösche alle Leerzeilen am Ende einer Datei
sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' # funktioniert bei allen seds
sed -e :a -e '/^\n*$/N;/\n$/ba' # ditto, außer bei gsed 3.02.*
# Lösche die letzte Zeile jedes Absatzes
sed -n '/^$/{p;h;};/./{x;/./p;}'
SPEZIELLE EINSATZGEBIETE:
# Entferne nroff "overstrikes" (char, Rückschritt) aus Man-Seiten.
# Die 'echo' Anweisung braucht eventuell die Option -e für die Unix System V shell oder bash.
sed "s/.`echo \\\b`//g" # Doppelte Anfürungszeichen werden in Unix-Umgebungen benötigt.
sed 's/.^H//g' # In bash/tcsh, Ctrl-V und dann Ctrl-H drücken
sed 's/.\x08//g' # Hex-Angabe für sed 1.5, GNU sed, ssed
# nur die Usenet/E-Mail Kopfzeilen
sed '/^$/q' # Löscht alles nach der ersten Leerzeile
# nur die Usenet/E-Mail Nachrichtentext
sed '1,/^$/d' # Löscht alles bis zur ersten Leerzeile
# Die Betreffzeile einer E-Mail, aber ohne das "Subject: " am Zeilenanfang
sed '/^Subject: */!d; s///;q'
# Die Antwortadresse einer E-Mail
sed '/^Reply-To:/q; /^From:/h; /./d;g;q'
# Extrahiert die E-Mail-Adresse aus der Antwortadresse des vorherigen Scripts
sed 's/ *(.*)//; s/>.*//; s/.*[:<] *//'
# Ein Größer-Zeichen an jedem Zeilenanfang einfügen (Nachricht zitieren)
sed 's/^/> /'
# Größerzeichen am Zeilananfang löschen (Macht vorheriges script rückgängig)
sed 's/^> //'
# Entferne die meisten HTML-Auszeichnungen (inklusive die über mehrere Zeilen)
sed -e :a -e 's/<[^>]*>//g;/</N;//ba'
# Multi-part uuencodierte Binärdateien auspacken
# und fehlerhafte Kopfzeilen entfernen, so dass nur die uuencodierten Daten
# übrig bleiben.
# Die übergebenen Dateien müssen in der richtigen Reihenfolge sein.
# Möglichkeit 1 kann auf der Kommandozeile ausgeführt werden,
# Möglichkeit 2 kann als Unix-Shell-Script ausgeführt werden. (Basierend auf einem Script von Rahul Dhesi)
sed '/^end/,/^begin/d' file1 file2 ... fileX | uudecode # Möglichkeit 1
sed '/^end/,/^begin/d' "$@" | uudecode # Möglichkeit 2
# Sortiere die Absätze der Datei alphabetisch. Absätze werden durch Leerzeilen getrennt.
# GNU sed benutzt \v als vertikale Tabulatoren (Alternativ kann auch jedes andere,
# eindeutige Zeichen verwendet werden)
sed '/./{H;d;};x;s/\n/={NL}=/g' file | sort | sed '1s/={NL}=//;s/={NL}=/\n/g'
gsed '/./{H;d};x;y/\n/\v/' file | sort | sed '1s/\v//;y/\v/\n/'
# Komprimiere jede .TXT-Datei einzeln mit zip, lösche die Quelldatei
# und benenne jede ZIP-Datei mit dem Namen der TXT-Datei ohne .TXT
# (unter DOS: Der Befehl "dir /b" gibt die reinen Dateinamen in Großbuchstaben zurück)
echo @echo off >zipup.bat
dir /b *.txt | sed "s/^\(.*\)\.TXT/pkzip -mo \1 \1.TXT/" >>zipup.bat
TYPISCHE BEFEHLSZEILEN: Sed nimmt eine oder mehrere Bearbeitungsbefehle
entgegen und wendet diese, in der entsprechenden Reihenfolge auf jede
Zeile der Eingahe an. Nachdem alle Befehle auf die erste Zeile angewendet
wurden, wird diese ausgegeben, und die zweite Zeile wird zur Bearbeitung
entgegengenommen. Der Kreislauf wiederholt sich. Die vorhergehenden Beispiele
gehen davon aus, dass die Eingaben von der Standarteingabe (STDIN) kommen (d.h. z.B.
die Tastatur, bzw. i.d.R. wird die Eingabe von einer Pipe kommen).
Ein oderer mehrere Dateinamen können an die Befehlszeile angehängt werden,
fallt die Eingabe nicht von STDIN kommt. Die Ausgaben werden an die
Standarteingabe geschickt, d.h. i.d.R. auf dem Bildschirm ausgegeben.
Daher gilt:
cat filename | sed '10q' # Benutzt die "Pipe" zur Eingabe
sed '10q' filename # gleicher Effekt, spart das unnötige "cat"
sed '10q' filename > newfile # Leitet die Ausgabe um ins Dateisystem
Weitere Erklärungen des Sysntax, inklusive der Möglichkeit Befehle
von einer Datei statt von der Befehlszeile zu benutzen sind in "sed &
awk, 2nd Edition," von Dale Dougherty und Arnold Robbins (O'Reilly,
1997; http://www.ora.com), "UNIX Text Processing," von Dale Dougherty
und Tim O'Reilly (Hayden Books, 1987) oder in den Anleitungen von Mike Arst
die als U-SEDIT2.ZIP au vielen Seiten zum Download bereit stehen zu finden.
Um alle Möglichkeiten von sed zu nutzen, muss man Reguläre Ausdrücke
verstehen. Hierfür können folgende Bücher herangezogen werden:
"Mastering Regular Expressions" von Jeffrey Friedl (O'Reilly, 1997).
Die Manual-Seiten ("man") auf Unix-Systemen können auch hilfreich sein.
("man sed", "man regexp", oder der Abschnitt über Reguläre Ausdrücke in
"man ed"), aber einige dieser Seiten sind für ihren Schwierigkeitsgrad
bekannt. Sie sind nicht als Einführung für neue Sed- oder Regex-Benutzer
geschrieben, sondern als Referenz für diejenigen, die diese Werkzeuge
bereits beherrschen.
BENUTZUNG VON HOCHKOMMAS:
Die angeführten Beispiele schließen die Anweisungen in einfache
Anführungszeichen ('...') anstatt der doppelten ("...") ein, da
sed typischerweise in einer Unix-Umgebung zur Anwendung kommt.
Einfache Anführungszeichen hindern die Unix-Shell (Kommandozeile)
daran, das Dollarzeichen ($) und die umgekehrten Hochkommas (`...`)
auszuwerten, wie dies bei der verwendung von doppelten Anführungszeichen
("...") der Fall wäre.
Benutzer der "csh" Shell und deren Weiterentwicklungen müssen ausserdem
trotz verwendung von einfachen Anführungszeichen alle Ausrufezeichen (!)
mit einem Rückwärtsstrich schützen (z.B. "\!") um die Beispiele korrekt
ausführen zu können.
DOS-Versionen von sed benötigen allesamt doppelte Anführungszeichen ("...")
um die Befehle herum.
DIE BENUTZUNG VON '\t' IN SED-SCRIPTEN:
Der Deutlichkeit halber haben wir in diesem Dokument die Zeichenfolge '\t'
benutzt, um das Tabulatorzeichen (0x09) darzustellen. Die meisen Versionen
von sed kennen jedoch diese Darstellung nicht.
Bei der Eingabe der Befehle muss '\t' durch drücken der Tabulatortaste
eingegeben werden. '\t' wird von awk, perl, HHsed, sedmod, und GNU sed
v3.02.80 in regulären Ausdrücken als Tabulator anerkannt.
VERSIONEN VON SED:
Die unterschiedlichen sed-versionen haben unterschied und man muss auch
mit leichten Unterschieden im Syntax rechnen. Besonders die Benutzung von
Marken (:name) oder Verzweigungen (b,t) innerhalb von Kommandos (nicht an
deren Ende) werden von vielen Versionen nicht unterstützt.
Wir haben eine Schreibweise gewählt, die sich mit den meisten Versionen
von sed benutzen lässt, auch wenn die beliebten GNU-Versionen von sed eine
elegantere Schreibweise erlauben würden.
Wem man einen ziemlich langen Befehl wie den folgenden sieht:
sed -e '/AAA/b' -e '/BBB/b' -e '/CCC/b' -e d
ist es gut zu wissen, dass man diesen mit GNU-sed zu folgendem kürzen kann:
sed '/AAA/b;/BBB/b;/CCC/b;d' # oder sogar
sed '/AAA\|BBB\|CCC/b;d'
Ausserdem ist zu beachten, dass obwohl viele Versionen von sed einen Befehl
wie "/one/ s/RE1/RE2/" erlauben, einige "/one/! s/RE1/RE2/" NICHT erlauben,
was ein Leerzeichen vor dem 's' enthält. Bei der Eingabe der Befehle muss hier
das Leerzeichen weggelassen werden.
GESCHWINDIGKEITSOPTIMIERUNG:
Falls die ausfürungsgeschwindigkeit wegen großen Dateien oder langsamen CPUs
bzw. Festplatten erhöht werden muss, können Ersetzungen beschleunigt werden,
indem der gesuchte Ausdruck vor dem "s/.../.../" genannt wird. Es gilt:
sed 's/foo/bar/g' filename # Normales Suchen & Ersetzen
sed '/foo/ s/foo/bar/g' filename # Schnellere Version
sed '/foo/ s//bar/g' filename # sed Kurzschreibweise
Wenn bei der Auswahl oder Löschung von Zeilen nur Zeilen aus dem Dateianfang
ausgegeben werden sollen, verkürzt bei großen Dateien ein "quit" Befehl (q)
die Bearbeitungszeit erheblich. Daher:
sed -n '45,50p' filename # Ausgabe der Zeilen 45-50 einer Datei
sed -n '51q;45,50p' filename # dito, aber biel schneller.
Falls Sie weitere Scripte haben, und diese für dieses Dokument zur Verfügung
stellen möchten, oder falls Sie Fehler in diesem Dokument gefunden haben,
senden Sie bitte eine E-Mail an den Verwalter dieser Sammlung. (Fehler in der
Übersetzung melden Sie bitte dem Übersetzer.) Bitte geben Sie die
Problemstellung, die benutzte sed-Version und das benutze Betriebssystem an.
Um als "Einzeiler" zu gelten, darf die Befehlszeile höchstens 65 Zeichen
lang sein. Verschiedene Befehle in diesem Dokument wurden von den folgenden
Personen beigesteuert:
Al Aab # Initiator der "seders" Mailing-Liste
Edgar Allen # Diverses
Yiorgos Adamopoulos # Diverses
Dale Dougherty # Author von "sed & awk"
Carlos Duarte # Author von "do it with sed"
Eric Pement # Author dieses Dokuments
Ken Pizzini # Author von GNU sed v3.02
S.G. Ravenhall # Das großartige De-HTML-Script
Greg Ubben # Viele Beitrage und Hilfe
Temporäres Verzeichnis erstellen:
{{{
temporaeres_Verzeichnis_erstellen()
{
if [[ "$1" != "" ]]
then
tmpdir=$1
fi
#falls die Variable tmpdir noch nicht belegt ist, wird ein neuer Name erstellt
[[ -z $tmpdir ]] && tmpdir=/tmp/$(basename $0)_$$_tmp
if ! mkdir -p $tmpdir 2>/dev/null
then
echo "Kann temporaeres Verzeichnis nicht anlegen!"
exit 1
fi
if [ ! -w $tmpdir ]
then
echo "Keine Schreibberechtigung im temporaeren Verzeichnis $tmpdir!"
exit 1
fi
echo "Temporaeres Verzeichnis: " $(readlink -f $tmpdir) && $VERBOSE_ON
return 0
}
}}}
!Grundlagen
1.) Erstelle ein Script, das "Hallo Welt!" auf die Konsole schreibt.
2.) Erstelle ein zweites Script:
* ermittle deinen Usernamen und speicher ihn in eine Variable
* erzeuge daraus einen Dateinamen mit der Endung .log und speicher ihn in eine Variable
* Lenke die Ausgabe deines ersten scripts in eine Datei mit diesem Namen
3.) Erstelle ein Script das ein Argument entgegennimmt, das deine log-Datei liest, und "Welt" durch das erste Argument ersetzt und danach die Datei ausgibt (unter Benutzung von cat/sed, siehe oben)