GELÖST: syntax error bei 'if !(test -e "abc")...'

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
dolphin
Beiträge: 362
Registriert: 01.05.2006 11:48:24

GELÖST: syntax error bei 'if !(test -e "abc")...'

Beitrag von dolphin » 18.03.2013 22:25:48

Guten Abend!

Ich habe folgenden Befehl:

Code: Alles auswählen

if !(test -e "abc"); then mkdir abc; fi
Wenn ich den in einem Shell-Skript ausführe, dann funktioniert er.

Führe ich ihn aber direkt in der BASH aus, ohne ihn in einem Shell-Skript eingebettet zu haben, dann erhalte ich:
bash: !: event not found
Na gut, dann mache ich halt ein \ vor das Ausrufezeichen:

Code: Alles auswählen

if \!(test -e "abc"); then mkdir abc; fi
Aber, es funktioniert immer noch nicht. Jetzt kommt das hier:
bash: syntax error near unexpected token `test'
Hat jemand eine Idee, wie ich es hinbekommen kann, dass dieser Befehl als Einzeiler ohne Skript funktioniert?

Danke im Voraus,
dolphin
Zuletzt geändert von dolphin am 11.06.2013 08:05:05, insgesamt 1-mal geändert.

Benutzeravatar
Natureshadow
Beiträge: 2157
Registriert: 11.08.2007 22:45:28
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Radevormwald
Kontaktdaten:

Re: AW: syntax error bei 'if !(test -e "abc")...'

Beitrag von Natureshadow » 18.03.2013 22:29:29

Code: Alles auswählen

[[ -e abc ]] || mkdir abc
Ich habe so was von absolut keine Ahnung, wie du auf deine Syntax da kommst …

Und unnötig ist es auch. Nach RTFM:

Code: Alles auswählen

mkdir -p abc
test aufzurufen ist fast immer falsch, es in einer Subshell zu tun noch falscher. Benutze außerdem keine Bash, denn… siehst du ja.

-nik

dolphin
Beiträge: 362
Registriert: 01.05.2006 11:48:24

Re: syntax error bei 'if !(test -e "abc")...'

Beitrag von dolphin » 18.03.2013 22:40:11

Danke! Das ist auch eine kreative Lösung. Ich hab jetzt das draus gemacht:

Code: Alles auswählen

test -e "abc" || mkdir "abc"
Funktioniert auch.

Aber, gibt es auch eine Variante mit Ausrufezeichen?

Falls nicht, nehm ich halt die "oder"-Variante.

dolphin

Benutzeravatar
Meillo
Moderator
Beiträge: 9239
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: syntax error bei 'if !(test -e "abc")...'

Beitrag von Meillo » 18.03.2013 22:48:56

dolphin hat geschrieben:Danke! Das ist auch eine kreative Lösung. Ich hab jetzt das draus gemacht:

Code: Alles auswählen

test -e "abc" || mkdir "abc"
Funktioniert auch.

Aber, gibt es auch eine Variante mit Ausrufezeichen?

Code: Alles auswählen

test ! -e "abc" && mkdir "abc"
;-)

In der Form wie du es hattest gibt es keine portable Variante.

So wie du es jetzt machst ist es portabel (abgesehen davon dass es manche alten Shells gibt deren test-builtin -e nicht kennt).

Was spricht gegen `mkdir -p abc'?
Use ed once in a while!

dolphin
Beiträge: 362
Registriert: 01.05.2006 11:48:24

Re: syntax error bei 'if !(test -e "abc")...'

Beitrag von dolphin » 18.03.2013 23:02:19

Hi!

Gegen ein "mkdir -p" spricht gar nichts. War mir halt nur nicht so geläufig.
Ich werde trotzdem die "||"-Variante brauchen.

Mein Anwendungsfall ist folgende Kopiervorlage, die ich mir gerade schreibe:

Code: Alles auswählen

mkdir -p ~/.nedit
test -e ~/.nedit/nedit.rc || cp -a 2_konfigurationen/nedit.rc ~/.nedit
Ist ja nun also ganz schick geworden dank eurer Hilfe.

:-)
dolphin

Benutzeravatar
Meillo
Moderator
Beiträge: 9239
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: syntax error bei 'if !(test -e "abc")...'

Beitrag von Meillo » 19.03.2013 08:24:40

dolphin hat geschrieben: Mein Anwendungsfall ist folgende Kopiervorlage, die ich mir gerade schreibe:

Code: Alles auswählen

mkdir -p ~/.nedit
test -e ~/.nedit/nedit.rc || cp -a 2_konfigurationen/nedit.rc ~/.nedit
So macht das Sinn: Fuer Verzeichnisse `mkdir -p' und fuer Dateien die ||-Variante.
Use ed once in a while!

Benutzeravatar
Natureshadow
Beiträge: 2157
Registriert: 11.08.2007 22:45:28
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Radevormwald
Kontaktdaten:

Re: AW: syntax error bei 'if !(test -e "abc")...'

Beitrag von Natureshadow » 19.03.2013 12:18:53

Code: Alles auswählen

mkdir -p foo && cp -na bar/bang foo/

dolphin
Beiträge: 362
Registriert: 01.05.2006 11:48:24

Re: AW: syntax error bei 'if !(test -e

Beitrag von dolphin » 19.03.2013 23:44:47

Natureshadow hat geschrieben:

Code: Alles auswählen

mkdir -p foo && cp -na bar/bang foo/
Ich weiss zwar nicht, was '-n' heisst, weil sowas in meiner man-Page nicht drin steht, aber
falls "-n" für "do not ask" oder sowas steht: Es wäre schon sinnvoll, wenn der Befehl eine vorhandene
Datei nicht überschreiben würde, wenn sie bereits existiert. Sie könnte ja einen anderen Inhalt
(älter oder neuer, aber auf jeden Fall wertvoll) enthalten.

deberik
Beiträge: 1177
Registriert: 30.09.2009 13:27:23

Re: AW: syntax error bei 'if !(test -e

Beitrag von deberik » 20.03.2013 00:20:09

dolphin hat geschrieben:
Natureshadow hat geschrieben:

Code: Alles auswählen

mkdir -p foo && cp -na bar/bang foo/
Ich weiss zwar nicht, was '-n' heisst, weil sowas in meiner man-Page nicht drin steht, aber
falls "-n" für "do not ask" oder sowas steht: Es wäre schon sinnvoll, wenn der Befehl eine vorhandene
Datei nicht überschreiben würde, wenn sie bereits existiert. Sie könnte ja einen anderen Inhalt
(älter oder neuer, aber auf jeden Fall wertvoll) enthalten.
o.O Verwendest du noch Lenny? Oder gar nicht Debian? Denn laut http://manpages.debian.net/cgi-bin/man.cgi ist -n seit Squeeze im Handbuch drin

Code: Alles auswählen

-n, --no-clobber
       do  not  overwrite  an  existing  file  (overrides a previous -i
       option)
Debians Paketbeschreibungen übersetzen? Hilf mit!

dolphin
Beiträge: 362
Registriert: 01.05.2006 11:48:24

Re: syntax error bei 'if !(test -e "abc")...'

Beitrag von dolphin » 20.03.2013 07:46:34

Ich migriere immer noch von Lenny nach Squeeze, und solange Squeeze nicht fertig ist, ist Lenny mein Produktivsystem.

Aber immerhin bin ich kurz vorm Wechsel:
  • Grub2 beherrsche ich nun genauso gut wie Grub Legacy. Umstellung war mühsam, aber es geht.
  • nVidia-Grafik läuft auf Squeeze nun wieder genauso bombenstabil wie auf Lenny. War eine verdammte Pfrickelei, aber jetzt geht es.
  • KDM-Login-Maske von KDE4 ist nun genauso stabil wie die alte KDE3-Variante (ich bin sogar die Bugs von KDE3 losgeworden). Bis ich herausgefunden hatte, wie ich KDM von KDE4 ohne KDE4, nur mit FVWM so laufen lassen kann, dass trotzdem der Mauszeiger nicht von den KDE4-Resten verkrüppelt wird, vergingen mehrere Manntage, in denen ich alle denkbaren Kombinationen zwischen Grafiktreiber, Display-Manager, Window-Manager und Desktop-Environment durchprobiert habe, bis ich ENDLICH eine Kombination gefunden habe, die zueinander passt.
  • Bei FVWM hab ich wieder ein Debian-Menü hinbekommen. Jetzt fühlt es sich unter Squeeze wieder an wie unter Lenny. Yeah!!! Danke an die FVWM-Mailingliste!
Jetzt arbeite ich gerade am Deployment der Squeeze-Templates für meine 4 Host-Systeme. Dann kommt noch KVM für die Virtualisierung. Das muss ich so hinbekommen, dass die Gastsysteme NICHT Amok laufen, wenn ich Tastatur und Maus gleichzeitig benutze. Das nervt gewaltig. Aber das Problem werde ich auch noch lösen, indem ich NICHT das KVM von Squeeze benutze, sondern die Variante, die ich im Sommer 2012 aus dem Netz heruntergeladen habe.

Es gibt Arbeit ohne Ende, diese Umstellung von Lenny auf Squeeze ist eine riesige Bastelarbeit mit viel Probieren, Verwerfen, Probieren, Verwerfen, Probieren, Verwerfen, Probieren, Verwerfen, Probieren, Verwerfen, Probieren, Verwerfen und so weiter.

Wenn es dann noch irgendwelche "-n"-Optionen für einen Copy-Befehl gibt, die jetzt neu sind, dann ist es zwar gut, dass mich mal jemand darauf hinweist, aber die Gedanken in meinem Kopf sind dann ungefähr so: "Toll! Mal wieder ein neues Feature. In 5 Jahren, wenn alles Andere stabil ist, werd ich es vielleicht mal nutzen."

Wenn man einfach nur ein "apt-get distupgrade" machen könnte, und Debian würde aus einem Lenny ein Squeeze machen, wäre das
ein Traum. Aber in der Praxis ist das absolute Utopie. Der Alptraum ging schon damit los, als ich (als Squeeze noch testing war) merkte, dass KDE3 durch KDE4 ersetzt wurde. Der Wechsel von KDE3 auf FVWM war zwar das Beste, was mir in meinem ganzen Linux-Leben passiert ist, aber hätte Squeeze KDE3 nicht abgeschafft, hätte ich diesen Schritt wahrscheinlich nie gemacht und wäre vielleicht schon 1 Jahr früher von Lenny auf Squeeze migriert (die Experimente mit Trinity hab ich trotzdem gemacht, viel Zeit verschwendet, festgestellt, das Trinity Grütze ist, und alles wieder verworfen).

So ist das Leben. 2 bis 4 Manntage im Monat Zeit und so viel Arbeit, um von Lenny nach Squeeze zu migrieren, und nebenbei gleich noch von 32 Bit auf 64 Bit umstellen und nebenbei ein Virtualisierungssystem erfinden, das beim nächsten Wechsel von Squeeze auf Wheezy nur noch einen Bruchteil der Arbeit erfordert, da kann es schon mal Jahre dauern, bis das Projekt fertig ist.

Ich hatte übrigens auf einem Squeeze-Prototyp-System von Ende 2011 sogar schon mal ein Wheezy in einer KVM lauffähig gehabt. 1 Jahr später hatte ich ein apt-get dist-upgrade gemacht, und danach war dieses Wheezy so kaputt, dass ich es wegwerfen musste, statt damit für ein bestimmtes Projekt ausnahmsweise mal produktiv arbeiten zu können.

dolphin

dolphin
Beiträge: 362
Registriert: 01.05.2006 11:48:24

Re: syntax error bei 'if !(test -e "abc")...'

Beitrag von dolphin » 11.06.2013 08:04:40

dolphin hat geschrieben:Guten Abend!

Ich habe folgenden Befehl:

Code: Alles auswählen

if !(test -e "abc"); then mkdir abc; fi
Wenn ich den in einem Shell-Skript ausführe, dann funktioniert er.

Führe ich ihn aber direkt in der BASH aus, ohne ihn in einem Shell-Skript eingebettet zu haben, dann erhalte ich:
bash: !: event not found
Na gut, dann mache ich halt ein \ vor das Ausrufezeichen:

Code: Alles auswählen

if \!(test -e "abc"); then mkdir abc; fi
Aber, es funktioniert immer noch nicht. Jetzt kommt das hier:
bash: syntax error near unexpected token `test'
Hat jemand eine Idee, wie ich es hinbekommen kann, dass dieser Befehl als Einzeiler ohne Skript funktioniert?

Danke im Voraus,
dolphin
Ich glaub, ich spinne!
Gerade kam mir spontan die Idee, zwischen Ausrufezeichen und Klammer ein Leerzeichen zu setzen.
Und was passiert? ES FUNKTIONIERT! HEUREKA!!!

So ist dann also die Lösung:

Code: Alles auswählen

if ! (test -e "abc"); then mkdir abc; fi
Totaaal einfach: Einfach ein Leerzeichen setzen...



(Problem war, dass ich heute einen Anwendungsfall hatte, bei dem mir && und || ohne ! nicht weitergeholfen hätten.
Für "Verschiebe eine Datei nur dann, wenn sie existiert, muss ich bei Anwendung von && und || negieren, und dann kann
ich auch gleich die menschenlesbarere IF-FI-Variante benutzen...")

Benutzeravatar
Meillo
Moderator
Beiträge: 9239
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: syntax error bei 'if !(test -e "abc")...'

Beitrag von Meillo » 11.06.2013 08:42:48

dolphin hat geschrieben: Ich glaub, ich spinne!
Gerade kam mir spontan die Idee, zwischen Ausrufezeichen und Klammer ein Leerzeichen zu setzen.
Und was passiert? ES FUNKTIONIERT! HEUREKA!!!
Es gibt einen Unterschied zwischen ``es erzeugt keinen Fehler'' und ``es tut genau was es soll''. (Versuch-und-Irrtum-Programmierung fuehrt oft zu Programmen die fast das tun was sie sollen.)
So ist dann also die Lösung:

Code: Alles auswählen

if ! (test -e "abc"); then mkdir abc; fi
In diesem Fall hast du Glueck gehabt, denn der Befehl tut tatsaechlich was er soll, allerdings ueber einen unnoetigen Umweg.

Ich muss aber zugeben, dass wir damals nicht wirklich auf dich eingegangen sind. Als du ``eine Variante mit Ausrufezeichen'' wolltest hast du die gekriegt. Eigentlich wolltest du aber einen Variante mit `if'. Die gibt's in dem Thread bislang nicht. Ich liefere sie deshalb hier nach. Beide Varianten sind portabel.

Code: Alles auswählen

if test ! -e "abc" ; then mkdir abc; fi

Code: Alles auswählen

if [ ! -e "abc" ] ; then mkdir abc; fi
Du hast in deinem Vorschlag die erste Variante gewaehlt, aber die Negierung vor das `test' gesetzt (und zudem einen unnoetige Subshell eingebaut). Mit dem Ausrufezeichen als Argument fuer `test' wird es von diesem verarbeitet und das ist POSIX-konform. Steht das Ausrufezeichen vor dem `test', dann muss es von der Shell verarbeitet werden. Moderne Shells (ksh, bash, etc) kennen `!' als reserviertes Wort und negieren damit den Exitstatus, dieses Verhalten ist aber nicht Teil von POSIX und wird von alten Shells nicht unbedingt unterstuetzt.

Wenn du gerne eine Variante mit `if' haben willst, statt der &&- und ||-Konstrukte, dann empfehle ich dir meine zweite Variante zu verwenden.

Für "Verschiebe eine Datei nur dann, wenn sie existiert, muss ich bei Anwendung von && und || negieren [...]
Nein, ein Negieren ist dafuer nicht noetig, da && der Negation von || entspricht und umgekehrt.

Code: Alles auswählen

test -e foo && mv foo bar
Vielleicht nochmal zur Klaerung: && in der Shell entspricht nicht dem logischen UND sondern bedeutet ``wenn das vorige Kommando erfolgreich war, dann fuehre das nachfolgende Kommando aus''.
Use ed once in a while!

dolphin
Beiträge: 362
Registriert: 01.05.2006 11:48:24

Re: GELÖST: syntax error bei 'if !(test -e "abc")...'

Beitrag von dolphin » 11.06.2013 09:40:30

Hallo Meillo,

herzlichen Dank für die informativen Details. Damit ist der Wert dieses Threads als Nachschlagewerk deutlich gestiegen.

Zu "test -e foo && mv foo bar":

Ja, das stimmt. Es funktioniert auch so. Letztendlich funktionieren die ||- und &&-Ansätze, weil die Interpreter faul sind:
  • Ein && muss die zweite Bedingung nicht testen, wenn die erste FALSE ist, denn es würde am Gesamtergebnis (FALSE) sowieso nichts ändern.
  • Ein || muss die zweite Bedingung nicht testen, wenn die erste TRUE ist, denn es würde am Gesamtergebnis (TRUE) sowieso nichts ändern.
Daher funktioniert das Ganze als Ersatz für If-Abfragen, und manche Programmierer nutzen das eben gern aus.

In meinem Fall wollte ich mehrere Dateien (*) von A nach B verschieben, und zwar nur dann, wenn Dateien vorhanden sind. Also, korrekt
nicht "eine Datei", wie vorher von mir angegeben, sondern "mehrere Dateien". Das funktionierte dann nicht, und ich verwarf den
Ansatz. Ich habe mittlerweile herausbekommen, dass ich "test" auf "*" gar nicht anwenden kann, und habe als Kompromiss
nun einfach ein

Code: Alles auswählen

mv /etc/xyz/* /etc/uvw/xyz
gemacht, und akzeptiere den Fehler, den das Kommando wirft, wenn das Verzeichnis "xyz" leer ist.

dolphin

Antworten