StdOut to StdErr

Für allgemeine Fragen zur Programmierung mit PureBasic.
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

StdOut to StdErr

Beitrag von ccode_new »

Hallo Leute,

ich habe da mal wieder eine Frage.

Wie kann ich dieses Bash-Konstrukt:

Code: Alles auswählen

3>&2 2>&1 1>&3
in PureBasic nachbilden?

Beispiel:

Code: Alles auswählen

#dialog = "whiptail"
;...

Procedure.i Termi_yesno(*this.termi_t, title.s, text.s, height.i, width.i, options.s="")
  Protected exit.i, prog.i
  If *this\run
    prog = RunProgram(#dialog, UnescapeString(options) + ~"--clear --title \"" + title + ~"\" --yesno \"" + text + ~"\" " + Str(height) + " " + Str(width), "", #PB_Program_Open | #PB_Program_Wait)
    If IsProgram(prog)
      While ProgramRunning(prog)
        ;...
      Wend
      exit = ProgramExitCode(prog)
      CloseProgram(prog)
      ProcedureReturn exit
    EndIf
  Else
    ProcedureReturn -1
  EndIf
EndProcedure

;...

prog = RunProgram(#dialog, "3>&2 2>&1 1>&3 "+ UnescapeString(options) + ~" --inputbox \"" + text + ~"\" " + Str(height) + " " + Str(width) + " " + init, "", #PB_Program_Open | #PB_Program_Error | #PB_Program_Wait)
;...
Danke!

Diese Befehle funktionieren nicht, oder ich wende sie höchstwahrscheinlich falsch an.

Code: Alles auswählen

!dup2(2, 3);
!dup2(1, 2);
!dup2(3, 1);
!close(3);
Zuletzt geändert von ccode_new am 18.01.2022 20:41, insgesamt 1-mal geändert.
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: StdOut to StdErr

Beitrag von NicTheQuick »

Das geht so einfach nicht, denn das Schreiben in filedescriptors wie 1, 2 und 3 übernimmt im Terminal deine Shell, z.B. Bash. In Purebasic musst du das entweder nachbilden mit #PB_Program_Open, #PB_Program_Connect oder du rufst einfach '/usr/bin/bash' auf und übergibst ihr genau dieses Konstrukt.

Abgesehen davon finde ich das hier höchst merkwürdig:

Code: Alles auswählen

3>&2 2>&1 1>&3
Das ist ja eine Zirkelbeziehung. 1 wird in 3 gepiped, 3 in 2 und 2 wieder in 1. Das ergibt keinen Sinn. Wo hast du das denn her?
3 musst du außerdem erst mal explizit erzeugen, soweit ich weiß.
Bild
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: StdOut to StdErr

Beitrag von ccode_new »

Hallo Nic,

danke für deine Antwort.

Also muss ich die Dialoge als komplettes Bash-Script aufrufen? Ok!

(Ich habe von Bash bisher null bis wenig Ahnung!)
NicTheQuick hat geschrieben: 18.01.2022 20:40 Wo hast du das denn her?
Zum Beispiel wird die Ausgabe der Eingabebox in Bash so abgefangen.
(Außer man geht den Weg über die Umleitung in eine Datei.)

#Linux-Bash

Code: Alles auswählen

COLOR=$(whiptail --inputbox "What is your favorite Color?" 8 39 Blue --title "Example Dialog" 3>&1 1>&2 2>&3)
                                                                        # A trick to swap stdout and stderr.
# Again, you can pack this inside if, but it seems really long for some 80-col terminal users.
exitstatus=$?
if [ $exitstatus = 0 ]; then
    echo "User selected Ok and entered " $COLOR
else
    echo "User selected Cancel."
fi

echo "(Exit status was $exitstatus)"
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: StdOut to StdErr

Beitrag von NicTheQuick »

Achso, ich verstehe jetzt.

Ich bezweifle das 'whiptail' außerhalb einer interaktiven Shell funktioniert. Das erwartet ja Tastatureingaben über stdin und muss die Dimensionen des Terminals wissen, die es nur über einen Terminalemulator erhält meines Wissens. Hast du vor das innerhalb von 'OpenConsole()' zu nutzen? Oder kompilierst du das Purebasic-Programm als Konsolenanwendung?

Du brauchst jedenfalls nicht die Ausgabeströme zu tauschen. Du kannst ja einfach 'ReadProgramError()' nutzen um das Ergebnis auszulesen.

Ich hab es jetzt aber auch eine Weile versucht hinzubekommen, was du vorhast, aber bin gescheitert. Ich hab es sogar mit virtuellen Dateien als Ausgabedatenstrom probiert:

Code: Alles auswählen

ImportC ""
	memfd_create(name.p-utf8, flags.l)
	read_fd.l(fd.l, *buf, count.l) As "read"
EndImport

Define fd.i = memfd_create("hi", 0)
If fd = -1
	Debug "Error"
	End
EndIf

Procedure.s read_(fd.i)
	Protected *buffer = AllocateMemory(1024)
	Protected length.i, out.s
	
	length = read_fd(fd, *buffer, 1024)
	
	out = PeekS(*buffer, length, #PB_UTF8)
	
	FreeMemory(*buffer)
	
	ProcedureReturn out
EndProcedure

Debug "los gehts"
 
prog.i = RunProgram("/usr/bin/whiptail", "--inputbox 'What is your favorite Color?' 8 39 Blue --title 'Example Dialog' --output-fd " + fd, "", #PB_Program_UTF8 | #PB_Program_Open | #PB_Program_Error | #PB_Program_Read)
If IsProgram(prog)
	While ProgramRunning(prog)
		Debug ReadProgramError(prog)
		CloseProgram(prog)
	Wend
EndIf

Debug read_(fd)
Debug "und ende"
Vielleicht hat noch jemand anderes eine Idee.

Aber vielleicht erklärst du kurz, was du überhaupt vorhast.
Bild
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: StdOut to StdErr

Beitrag von ccode_new »

NicTheQuick hat geschrieben: 18.01.2022 22:34 Du brauchst jedenfalls nicht die Ausgabeströme zu tauschen. Du kannst ja einfach 'ReadProgramError()' nutzen um das Ergebnis auszulesen.
Doch!
Ich muss die Ausgabeströme tauschen, weil sonst das Programm "whiptail" die Eingabe der Inputbox in stdout schreibt.

Aber man kann leider nicht die stdout - Ausgabe des Programms abfangen. (#PB_Program_Read geht nicht!)
NicTheQuick hat geschrieben: 18.01.2022 22:34 Vielleicht hat noch jemand anderes eine Idee.

Aber vielleicht erklärst du kurz, was du überhaupt vorhast.
Ersteres hoffe ich auch.

Das Programm soll ein vollständiges Konsolenprogramm sein. (Kein Windows-Manager /GUI - System nötig)
(OpenConsole() verwende ich)
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: StdOut to StdErr

Beitrag von NicTheQuick »

Ja, ich weiß warum #PB_Program_Read nicht geht. whiptail nutzt die grafischen Möglichkeiten des Terminals. Das ist wie wenn du bei Purebasic 'EnableGraphicalConsole(1)' nutzt. Und da steht auch in der Hilfe dabei:
Die Umleitung ("Redirection" über Pipes) arbeitet nicht korrekt, wenn der Grafikmodus aktiv ist.
Das trifft auch auf whiptail zu und deswegen funktioniert das Lesen von stdout und stderr nicht korrekt.
Das ganze funktioniert also nur korrekt in einer echten Shell.

Leider hab ich damit aber keine weitere Erfahrung, außer dass ich Dinge wie whiptail und Co auch schon in bash-Skripten benutzt habe. Aber ich es habe noch nie außerhalb von Shell-Skripten verwendet, also weder in C, noch Python, noch sonstwas und vor allem nicht in Purebasic. Da sind Pipes sowieso ungenügend implementiert.
Bild
Benutzeravatar
DrShrek
Beiträge: 1970
Registriert: 08.09.2004 00:59

Re: StdOut to StdErr

Beitrag von DrShrek »

geht daas nicht auch so:
1>NUL 2>NUL
Siehste! Geht doch....?!
PB*, *4PB, PetriDish, Movie2Image, PictureManager, TrainYourBrain, ...
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: StdOut to StdErr

Beitrag von NicTheQuick »

DrShrek hat geschrieben: 19.01.2022 21:54 geht daas nicht auch so:
1>NUL 2>NUL
Das ist glaube ich unter Windows so. Unter Linux müsste das eher '1>/dev/null' heißen.
Aber das will er ja gar nicht machen. Er will die Ausgaben von 1 und 2 vertauschen. Das ist aber nur in dem Bashskript notwendig, wenn man mit der '$()'-Notation arbeitet.
Bild
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: StdOut to StdErr

Beitrag von ccode_new »

Hallo,
ich verzichte auf das Bash-Zeug.
Es ist mir weder mit den C system() Befehl noch mit "diversen" exec -Befehlen gelungen.
Und das Rumgewurstel mit Umgebungsvariablen ist mir dann doch zu blöd.

Mit den PureBasic internen Consolenbefehlen kann man schon eine ganze Menge machen, aber ich werde mal auf curses(ncurses) umswitchen.
Damit geht an bestimmten Stellen deutlich mehr.

Anbei:
Die "newt"-Bibliothek ist zwar sehr genial, aber ist mir dann doch viel zu komplex.
Außerdem benötigt diese Lib den slang - Interpreter.
Im Quelltext-Verzeichnis von "newt" befindet sich außerdem im übrigen der "Quältext" von "whiptail".

____
Aber eigentlich müsste es trotzdem gehen die Ausgabe von "whiptail" zu erlangen.
Mit Python geht es ja auch. (pip3 install whiptail | pip3 install whiptail-dialogs)

Mit PureBasic und der internen Benutzung von Python geht es somit auch.

Also müsste es mit popen oder RunProgram eigentlich auch gehen.

Im Python-Script steht folgendes:
#Python3-Code:

Code: Alles auswählen

def run(
			self,
			control: str,
			msg: str,
			extra_args: Sequence[str] = (),
			extra_values: Sequence[str] = (),
			exit_on: Sequence[int] = (1, 255)
			) -> Response:
		"""

		:param control: The name of the control to run. One of ``"yesno"``, ``"msgbox"``, ``"infobox"``,
			``"inputbox"``, ``"passwordbox"``, ``"textbox"``, ``"menu"``, ``"checklist"``,
			``"radiolist"`` or ``"gauge"``
		:type control: str
		:param msg: The message to display in the dialog box
		:type msg: str
		:param extra_args: A sequence of extra arguments to pass to the control
		:param extra_values: A sequence of extra values to pass to the control
		:param exit_on: A sequence of return codes that will cause program execution to stop if
			:attr:`Whiptail.auto_exit` is :py:obj:`True`

		:return: The response returned by whiptail
		"""

		width = self.width
		height = self.height

		if self.height is None or self.width is None:
			w, h = get_terminal_size()

			if self.width is None:
				width = w - 10
				width = width - (width % 10)

			if self.height is None:
				height = h - 2
				height = height - (height % 5)

		cmd = [
				'whiptail',
				'--title',
				self.title,
				'--backtitle',
				self.backtitle,
				*list(extra_args),
				f'--{control}',
				"--",
				str(msg),
				str(height),
				str(width),
				*list(extra_values),
				]

		p = Popen(cmd, stderr=PIPE)
		out, err = p.communicate()

		if self.auto_exit and p.returncode in exit_on:
			print('User cancelled operation.')
			sys.exit(p.returncode)

		return Response(p.returncode, err)
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: StdOut to StdErr

Beitrag von ccode_new »

Hallo!
Es hat sich erledigt.

Ich habe mal noch ein bisschen rumprobiert.

Es funktioniert jetzt.

Nur mit der PureBasic internen "RunProgram"-Funktion bin ich gescheitert.
(Bei der Inputbox)

Beispiel:

Code: Alles auswählen

;Compile with Executable-Format: Console

EnableExplicit

#DIALOG = "whiptail"
Global pstr.s, i.i
Global.i pipe
Global pout.s{100}

OpenConsole("Program-Open-Test", #PB_UTF8)

;-c_test1
pstr = #DIALOG + ~" --gauge \"Loading...\" 6 50 0"

pipe = popen_(UTF8(pstr), UTF8("w"))

If( pipe <> #Null )
  For i=1 To 100
    Delay(100)
    fprintf_(pipe, UTF8(~"%d\n"), i);
    fflush_(pipe)
  Next
  pclose_(pipe)
EndIf


;-c_test2
pstr = #DIALOG + ~" --inputbox \"How is her condition?\" 0 0 Blue 3>&1 1>&2 2>&3"

pipe = popen_(UTF8(pstr), UTF8("r"))

If( pipe <> #Null )
  fgets_(@pout , 100 , pipe)
EndIf
pclose_(pipe)

PrintN("Output: "+PeekS(@pout, 20, #PB_UTF8))
Input()

;End

;-RunProgram Test
Global param.s = ~"--gauge \"Shutdown...\" 6 50 0"

Global prog.i, c.i

Global retstr.s

prog = RunProgram("whiptail",param,"",#PB_Program_Open|#PB_Program_Write|#PB_Program_UTF8)

If IsProgram(prog)
  While ProgramRunning(prog) And c <= 100
    For c=0 To 100
      Delay(100)
      WriteProgramStringN(prog, Str(c), #PB_UTF8)
    Next
  Wend
  CloseProgram(prog)
EndIf

CloseConsole()
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Antworten