Discussion:
find -> funktion
(zu alt für eine Antwort)
Alexander Goetzenstein
2024-05-12 11:47:57 UTC
Permalink
Hallo,
in einem Script möchte ich gefundene Dateien einer Funktion zuführen,
etwa so:


...
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}

find ./ -name *.txt -exec meinefunktion {} \;


So funktioniert das natürlich nicht, weil meinefunktion() kein
Shellscript o.ä. ist. Wie müsste ich vorgehen, um die Funktion für die
gefundenen Dateien auszuführen?
--
Gruß
Alex
Stefan Wiens
2024-05-12 12:06:20 UTC
Permalink
Post by Alexander Goetzenstein
Hallo,
in einem Script möchte ich gefundene Dateien einer Funktion zuführen,
...
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
find ./ -name *.txt -exec meinefunktion {} \;
^-type f wäre da noch zu empfehlen
Post by Alexander Goetzenstein
So funktioniert das natürlich nicht, weil meinefunktion() kein
Shellscript o.ä. ist. Wie müsste ich vorgehen, um die Funktion für die
gefundenen Dateien auszuführen?
Einen Wrapper konstruieren, so dass es (per execve(2))
ausführbar ist. Das muss kein Shellskript sein.
Die Ausführungsumgebung für meinefunktion()
musst du natürlich bereitstellen.
--
Stefan
Alexander Goetzenstein
2024-05-12 12:21:18 UTC
Permalink
Hallo,
Post by Stefan Wiens
Post by Alexander Goetzenstein
Hallo,
in einem Script möchte ich gefundene Dateien einer Funktion zuführen,
...
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
find ./ -name *.txt -exec meinefunktion {} \;
^-type f wäre da noch zu empfehlen
Post by Alexander Goetzenstein
So funktioniert das natürlich nicht, weil meinefunktion() kein
Shellscript o.ä. ist. Wie müsste ich vorgehen, um die Funktion für die
gefundenen Dateien auszuführen?
Einen Wrapper konstruieren, so dass es (per execve(2))
ausführbar ist. Das muss kein Shellskript sein.
Die Ausführungsumgebung für meinefunktion()
musst du natürlich bereitstellen.
das verstehe ich nicht. Also habe ich ein wenig nach execve gegooglet,
und was ich da gefunden habe, sieht eher aus nach Verwendung in
C-Programmen als in Shellscripts.
--
Gruß
Alex
Peter J. Holzer
2024-05-12 12:43:08 UTC
Permalink
Post by Alexander Goetzenstein
Post by Stefan Wiens
Post by Alexander Goetzenstein
in einem Script möchte ich gefundene Dateien einer Funktion zuführen,
...
meinefunktion()
{
[...]
Post by Alexander Goetzenstein
Post by Stefan Wiens
Post by Alexander Goetzenstein
}
find ./ -name *.txt -exec meinefunktion {} \;
^-type f wäre da noch zu empfehlen
Post by Alexander Goetzenstein
So funktioniert das natürlich nicht, weil meinefunktion() kein
Shellscript o.ä. ist. Wie müsste ich vorgehen, um die Funktion für die
gefundenen Dateien auszuführen?
Einen Wrapper konstruieren, so dass es (per execve(2))
ausführbar ist. Das muss kein Shellskript sein.
Die Ausführungsumgebung für meinefunktion()
musst du natürlich bereitstellen.
das verstehe ich nicht. Also habe ich ein wenig nach execve gegooglet,
und was ich da gefunden habe, sieht eher aus nach Verwendung in
C-Programmen als in Shellscripts.
find ist ein C-Programm ;-)[1]

find verwendet execve, um das, was Du mit -exec angegeben hast,
auszuführen. Das muss also ein ausführbares Programm sein (ob ein Binary
Executable oder ein Script, ist egal).

Am einfachsten ist es, wenn Du meinefunktion() in ein Shell-Script
auslagerst.

(Mir ist nicht klar, was Stefan mit "das muss kein Shellskript sein"
meint. Die Funktion ist Shell-Code, also muss sie von einer Shell
ausgeführt werden. Natürlich kann man drumherum noch einen Wrapper in C,
Python, Java, Snobol, ... schreiben, aber der ruft dann nur eine Shell
auf, also sehe ich darin keinen Vorteil, außer vielleicht, wenn Du schon
eine Library von Shell-Funktionen in einem eigenen File hast.)

hp

[1] Ist aber irrelevant. Execve ist der Systemcall. Im Endeffekt muss
den für diesen Zweck jedes Programm aufrufen, egal in welcher
Sprache es geschrieben ist. Auch ein Shell-Script oder Python-Script
ruft indirekt execve auf, wann immer es ein anderes Programm
startet, auch wenn der String "execve" nirgends im Script vorkommt.
Das macht halt der Interpreter (Shell bzw. Python) hinter den
Kulissen.
Stefan Wiens
2024-05-12 12:46:50 UTC
Permalink
Post by Alexander Goetzenstein
Hallo,
Post by Stefan Wiens
Post by Alexander Goetzenstein
Hallo,
in einem Script möchte ich gefundene Dateien einer Funktion zuführen,
...
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
find ./ -name *.txt -exec meinefunktion {} \;
^-type f wäre da noch zu empfehlen
Post by Alexander Goetzenstein
So funktioniert das natürlich nicht, weil meinefunktion() kein
Shellscript o.ä. ist. Wie müsste ich vorgehen, um die Funktion für die
gefundenen Dateien auszuführen?
Einen Wrapper konstruieren, so dass es (per execve(2))
ausführbar ist. Das muss kein Shellskript sein.
Die Ausführungsumgebung für meinefunktion()
musst du natürlich bereitstellen.
das verstehe ich nicht. Also habe ich ein wenig nach execve gegooglet,
und was ich da gefunden habe, sieht eher aus nach Verwendung in
C-Programmen als in Shellscripts.
Damit es find per exec aufrufen kann, muss es halt aufrufbar sein.

Dein Beispiel meinefunktion(), ein Shellskript, könnte man, da keine
Argumente erforderlich sind, per
exec sh c- 'echo $1\
if [ -f $1 ]; then\
head -n 10 $1\
tail -n 20 $1\
fi'
einreichen.

Das Quoting ist ausbaufähig.


Aber deine reale Funktion ist anscheinend kein Shellskript.

Wenn es Python ist, könnte man es mit python -c versuchen,
ähnlich bei Perl mit perl -e. Aber meist muss man allerlei
Bibliotheken einbinden, damit es läuft. Dann kann man sein
Skript auch gleich in eine ausführbare Datei packen.
--
Stefan
Alexander Goetzenstein
2024-05-12 13:02:27 UTC
Permalink
Hallo,
Post by Stefan Wiens
Post by Alexander Goetzenstein
Hallo,
Post by Stefan Wiens
Post by Alexander Goetzenstein
Hallo,
in einem Script möchte ich gefundene Dateien einer Funktion zuführen,
...
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
find ./ -name *.txt -exec meinefunktion {} \;
^-type f wäre da noch zu empfehlen
Post by Alexander Goetzenstein
So funktioniert das natürlich nicht, weil meinefunktion() kein
Shellscript o.ä. ist. Wie müsste ich vorgehen, um die Funktion für die
gefundenen Dateien auszuführen?
Einen Wrapper konstruieren, so dass es (per execve(2))
ausführbar ist. Das muss kein Shellskript sein.
Die Ausführungsumgebung für meinefunktion()
musst du natürlich bereitstellen.
das verstehe ich nicht. Also habe ich ein wenig nach execve gegooglet,
und was ich da gefunden habe, sieht eher aus nach Verwendung in
C-Programmen als in Shellscripts.
Damit es find per exec aufrufen kann, muss es halt aufrufbar sein.
Dein Beispiel meinefunktion(), ein Shellskript, könnte man, da keine
Argumente erforderlich sind, per
exec sh c- 'echo $1\
if [ -f $1 ]; then\
head -n 10 $1\
tail -n 20 $1\
fi'
einreichen.
Das Quoting ist ausbaufähig.
Aber deine reale Funktion ist anscheinend kein Shellskript.
die zitierte Funktion meinefunktion() ist Teil desselben Shellscripts
wie die aufrufende Zeile mit find -name *.txt -exec...
Wobei es nicht unbedingt find sein muss, wenn es andere Möglichkeiten
gibt, das dient eher der Darstellung, was ich erreichen will.
Post by Stefan Wiens
Wenn es Python ist, könnte man es mit python -c versuchen,
ähnlich bei Perl mit perl -e. Aber meist muss man allerlei
Bibliotheken einbinden, damit es läuft. Dann kann man sein
Skript auch gleich in eine ausführbare Datei packen.
Mit Mühe finde ich mich in einfachen Shellscripten zurecht, mit Python
oder Perl habe ich nichts am Hut.
--
Gruß
Alex
Stefan Wiens
2024-05-12 13:15:29 UTC
Permalink
Post by Alexander Goetzenstein
Post by Stefan Wiens
Post by Alexander Goetzenstein
Post by Stefan Wiens
Post by Alexander Goetzenstein
Hallo,
in einem Script möchte ich gefundene Dateien einer Funktion zuführen,
...
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
find ./ -name *.txt -exec meinefunktion {} \;
^-type f wäre da noch zu empfehlen
Post by Alexander Goetzenstein
So funktioniert das natürlich nicht, weil meinefunktion() kein
Shellscript o.ä. ist. Wie müsste ich vorgehen, um die Funktion für die
gefundenen Dateien auszuführen?
Einen Wrapper konstruieren, so dass es (per execve(2))
ausführbar ist. Das muss kein Shellskript sein.
Die Ausführungsumgebung für meinefunktion()
musst du natürlich bereitstellen.
das verstehe ich nicht. Also habe ich ein wenig nach execve gegooglet,
und was ich da gefunden habe, sieht eher aus nach Verwendung in
C-Programmen als in Shellscripts.
Damit es find per exec aufrufen kann, muss es halt aufrufbar sein.
Dein Beispiel meinefunktion(), ein Shellskript, könnte man, da keine
Argumente erforderlich sind, per
exec sh c- 'echo $1\
if [ -f $1 ]; then\
head -n 10 $1\
tail -n 20 $1\
fi'
einreichen.
Das Quoting ist ausbaufähig.
Aber deine reale Funktion ist anscheinend kein Shellskript.
die zitierte Funktion meinefunktion() ist Teil desselben Shellscripts
wie die aufrufende Zeile mit find -name *.txt -exec...
Wobei es nicht unbedingt find sein muss, wenn es andere Möglichkeiten
gibt, das dient eher der Darstellung, was ich erreichen will.
Das klingt, als möchtest du per find -exec
eine in einem Shellscript definierte Funktion aufrufen.

Da find(3) außerhalb der Shell läuft, hat es keinen Zugriff
auf die dort internen Funktionen.

Vielleicht könnte man die per exec aufgerufene Shell
das Skript laden lassen und so die interessante
Funktion aufrufen? Aber die Kommandozeilenparameter
müssen stimmen.

Auf interne Variablen der aufrufenden Shell hat man
keinen Zugriff.
--
Stefan
Alexander Goetzenstein
2024-05-12 20:09:43 UTC
Permalink
Hallo,
Post by Stefan Wiens
Post by Alexander Goetzenstein
Post by Stefan Wiens
Post by Alexander Goetzenstein
Post by Stefan Wiens
Post by Alexander Goetzenstein
Hallo,
in einem Script möchte ich gefundene Dateien einer Funktion zuführen,
...
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
find ./ -name *.txt -exec meinefunktion {} \;
^-type f wäre da noch zu empfehlen
Post by Alexander Goetzenstein
So funktioniert das natürlich nicht, weil meinefunktion() kein
Shellscript o.ä. ist. Wie müsste ich vorgehen, um die Funktion für die
gefundenen Dateien auszuführen?
Einen Wrapper konstruieren, so dass es (per execve(2))
ausführbar ist. Das muss kein Shellskript sein.
Die Ausführungsumgebung für meinefunktion()
musst du natürlich bereitstellen.
das verstehe ich nicht. Also habe ich ein wenig nach execve gegooglet,
und was ich da gefunden habe, sieht eher aus nach Verwendung in
C-Programmen als in Shellscripts.
Damit es find per exec aufrufen kann, muss es halt aufrufbar sein.
Dein Beispiel meinefunktion(), ein Shellskript, könnte man, da keine
Argumente erforderlich sind, per
exec sh c- 'echo $1\
if [ -f $1 ]; then\
head -n 10 $1\
tail -n 20 $1\
fi'
einreichen.
Das Quoting ist ausbaufähig.
Aber deine reale Funktion ist anscheinend kein Shellskript.
die zitierte Funktion meinefunktion() ist Teil desselben Shellscripts
wie die aufrufende Zeile mit find -name *.txt -exec...
Wobei es nicht unbedingt find sein muss, wenn es andere Möglichkeiten
gibt, das dient eher der Darstellung, was ich erreichen will.
Das klingt, als möchtest du per find -exec
eine in einem Shellscript definierte Funktion aufrufen.
Da find(3) außerhalb der Shell läuft, hat es keinen Zugriff
auf die dort internen Funktionen.
Vielleicht könnte man die per exec aufgerufene Shell
das Skript laden lassen und so die interessante
Funktion aufrufen? Aber die Kommandozeilenparameter
müssen stimmen.
Auf interne Variablen der aufrufenden Shell hat man
keinen Zugriff.
Danke für die Anregung. Jetzt habe ich es so gemacht, dass find das
Script selbst aufruft mit dem Funktionsnamen als ersten Parameter. Das
sieht dann so aus:


meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}


if [ "$1" == "meinefunktion" ]; then
meinefunktion $PARAMETER $DATEI
exit 0
fi


find ./ -name *.txt -exec $(basename $0) meinefunktion $PARAMETER {} \;"



Etwas umständlich, aber so brauche ich keine Helferdateien.
--
Gruß
Alex
Martin Vaeth
2024-05-13 05:31:02 UTC
Permalink
Post by Alexander Goetzenstein
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
if [ "$1" == "meinefunktion" ]; then
meinefunktion $PARAMETER $DATEI
exit 0
fi
find ./ -name *.txt -exec $(basename $0) meinefunktion $PARAMETER {} \;
Etwas umständlich, aber so brauche ich keine Helferdateien.
Wie ich in einem anderen Posting schrieb: Es ist oft nur eine Frage
der Code-Organisation. Wenn das Ganze sowieso ein Script ist, kannst
Du es einfach als Argument von find hinpacken:

find ./ -name *.txt -exec /bin/sh -c '
meinefunktion()
{
printf "%s\n" "$1"
if [ -f "$1" ]; then
head -n 10 "$1"
tail -n 20 "$1"
fi
}

if [ "$1" == "meinefunktion" ]; then
meinefunktion $PARAMETER "$1"
exit 0
fi
' sh $PARAMETER {} \;
Stefan Ram
2024-05-12 20:24:57 UTC
Permalink
Post by Alexander Goetzenstein
Mit Mühe finde ich mich in einfachen Shellscripten zurecht, mit Python
oder Perl habe ich nichts am Hut.
Das klingt so, als sei für Dich Python schwieriger als Shell.
Ich empfinde dies eigentlich gerade als umgekehrt.

Aber, weil dies hier die shell-Gruppe ist
(experimenteller ungetesteter Code ohne jede Gewähr):

meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}

for file in $(find . -type f -name "*.txt"); do
meinefunktion "$file"
done

. Alternativ, für die Nörgler:

find . -type f -name "*.txt" | while read file; do
meinefunktion "$file"
done

.
Stefan Ram
2024-05-12 20:30:26 UTC
Permalink
Post by Stefan Ram
find . -type f -name "*.txt" | while read file; do
meinefunktion "$file"
done
Mit "print0" wie bei Tim ist es natürlich noch besser!
Stefan Ram
2024-05-12 20:47:46 UTC
Permalink
Post by Stefan Ram
Das klingt so, als sei für Dich Python schwieriger als Shell.
Ich empfinde dies eigentlich gerade als umgekehrt.
Man könnte das Kommando "tail" natürlich von Python aus aufrufen,
aber wenn man "head" und "tail" beide mit Python realisieren will,
ist das "tail" wohl immer etwas schwierig. Insbesondere zerbrechen
sich die Leute wohl den Kopf, wie man ein bei einer großen Datei
effizientes "tail" in Python realisieren kann. Aber hier ist ein
Beispiel, wie man es in Python realisieren könnte:

import glob

def meinefunktion( file_path ):
print( file_path )
tail = []
with open( file_path )as source:
for i, line in enumerate( source ):
if i < 10: print( line, end='' )
tail.append( line )
if len( tail )> 20: tail = tail[ -20: ]
for line in tail: print( line, end='' )

def find_txt_files( directory ):
txt_files = glob.glob( f"{directory}/**/*.txt", recursive=True )
for file_path in txt_files: meinefunktion( file_path )

find_txt_files( "." )
Stefan Ram
2024-05-18 01:32:07 UTC
Permalink
Post by Stefan Ram
Man könnte das Kommando "tail" natürlich von Python aus aufrufen,
aber wenn man "head" und "tail" beide mit Python realisieren will,
ist das "tail" wohl immer etwas schwierig.
Ich habe hier unter Windows eine Sammlung von "Unix-Tools", darunter
ein "tail", das ich gerade brauchte. Bei einer Textdatei unter einem
GB, war es schnell, aber bei einer Textdatei mit mehreren GB langsam.

Eine mbox-Datei wurde dann von diesem "tail" als "binäre"
Datei angesehen. Aber die Option "-c" war dann hier anscheinend
fehlerhaft, so daß das "tail" sich dann wie "head" verhielt.
Daraufhin mußte ich eine andere Lösung suchen und kam auf Python.

Die folgende Python-Funktion habe ich als Abwandlung meiner vor
einigen Tagen hier geposteten Funktion geschrieben.

import collections

def tail( file_path, n ):
tail = collections.deque()
with open( file_path, "br" )as source:
source.seek( -n*80, 2 )
for line in source: # Liest "Zeilen" auch bei binärer Datei!
tail.append( line )
if len( tail )> n: tail.popleft()
for line in tail:
print( line.strip( b'\r\n' ))

. Das ist nicht ganz universell, aber erfüllt hier schon den
Zweck, das Ende einer riesigen mbox-Datei zu sehen. Statt "list"
verwende ich jetzt "deque", in der Hoffnung, daß das "popleft" dort
effizienter ist als der vorherige Slice. Das "source.seek( -n*80, 2 )"
ist eine etwas gewagte Optimierung unter der Annahme, daß solch
ein "seek" unterstützt wird und Zeilen im Mittel nicht mehr als 80
Zeichen haben. Wenn der seek-Aufruf entfernt wird, sollte das tail
immer noch funktionieren, aber vielleicht dann langsamer sein.

In diesem speziellen Fall ist die Python-Lösung hier schnell und
löst ein Problem, das dieses speziellen tail-Programm hier nicht
lösen konnte.

Stefan Wiens
2024-05-12 13:41:50 UTC
Permalink
Post by Alexander Goetzenstein
Hallo,
in einem Script möchte ich gefundene Dateien einer Funktion zuführen,
...
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
find ./ -name *.txt -exec meinefunktion {} \;
So funktioniert das natürlich nicht, weil meinefunktion() kein
Shellscript o.ä. ist. Wie müsste ich vorgehen, um die Funktion für die
gefundenen Dateien auszuführen?
Wenn du find nichts Ausführbares für die exec-Option
anzubieten hast, kannst du den Output selbst zerschnippeln.
GNU find hat die Option -print0. Ich schätze
-exec "printf %s\0" als äquivalent ein.
--
Stefan
Tim Landscheidt
2024-05-12 13:52:46 UTC
Permalink
Post by Stefan Wiens
Post by Alexander Goetzenstein
in einem Script möchte ich gefundene Dateien einer Funktion zuführen,
...
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
find ./ -name *.txt -exec meinefunktion {} \;
So funktioniert das natürlich nicht, weil meinefunktion() kein
Shellscript o.ä. ist. Wie müsste ich vorgehen, um die Funktion für die
gefundenen Dateien auszuführen?
Wenn du find nichts Ausführbares für die exec-Option
anzubieten hast, kannst du den Output selbst zerschnippeln.
GNU find hat die Option -print0. Ich schätze
-exec "printf %s\0" als äquivalent ein.
… beispielsweise in der Form (ungetestet):

| find ./ -name *.txt -print0 | while IFS= read -d '' filename; do
| meinefunktion "$filename"
| done

Obacht: Durch die Pipeline wird eine neue Subshell für die
while-Schleife erzeugt, so dass man „globale“ Variablen
nicht verändern kann.

Tim
Thomas Dorner
2024-05-12 14:29:40 UTC
Permalink
Post by Tim Landscheidt
| find ./ -name *.txt -print0 | while IFS= read -d '' filename; do
| meinefunktion "$filename"
| done
Obacht: Durch die Pipeline wird eine neue Subshell für die
while-Schleife erzeugt, so dass man „globale“ Variablen
nicht verändern kann.
Da es nur eine Pipe ist und der Teil danach der interessante ist, kann
man sich hier mit
| shopt -s lastpipe
behelfen.

Viele Grüße, Thomas
--
Adresse gilt nur kurzzeitig!
Ulli Horlacher
2024-05-13 07:19:30 UTC
Permalink
Post by Thomas Dorner
Da es nur eine Pipe ist und der Teil danach der interessante ist, kann
man sich hier mit
| shopt -s lastpipe
behelfen.
Funktioniert leider nicht:

***@juhu:~: echo $BASH_VERSION
5.1.16(1)-release
***@juhu:~: shopt -s lastpipe
***@juhu:~: shopt lastpipe
lastpipe on
***@juhu:~: export x=1
***@juhu:~: echo 2 | read x; echo $x
1
***@juhu:~: echo 2 | (read x; echo $x)
2
--
Ullrich Horlacher Server und Virtualisierung
Rechenzentrum TIK
Universitaet Stuttgart E-Mail: ***@tik.uni-stuttgart.de
Allmandring 30a Tel: ++49-711-68565868
70569 Stuttgart (Germany) WWW: https://www.tik.uni-stuttgart.de/
Christian Weisgerber
2024-05-13 10:33:48 UTC
Permalink
Post by Ulli Horlacher
Post by Thomas Dorner
Da es nur eine Pipe ist und der Teil danach der interessante ist, kann
man sich hier mit
| shopt -s lastpipe
behelfen.
Natürlich nicht, ist ja bash-spezifisch.
Post by Ulli Horlacher
5.1.16(1)-release
Da funktioniert es wie beschrieben:

lastpipe
If set, and job control is not active, the shell runs
the last command of a pipeline not executed in the
background in the current shell environment.

In einer interaktiven Shell ist Job Control standardmäßig aktiviert,
sonst nicht.
--
Christian "naddy" Weisgerber ***@mips.inka.de
Christian Weisgerber
2024-05-13 14:53:49 UTC
Permalink
Post by Thomas Dorner
Post by Ulli Horlacher
5.1.16(1)-release
lastpipe
If set, and job control is not active, the shell runs
the last command of a pipeline not executed in the
background in the current shell environment.
In einer interaktiven Shell ist Job Control standardmäßig aktiviert,
sonst nicht.
Und die Einschränkung mit der Job Control ist gut so. Im Vergleich
dazu führt eine interaktive ksh93 den letzten Befehl einer
Vordergrund-Pipeline ohne Subshell aus, was dann nicht so toll ist,
wenn man die Pipeline mit ^Z anhält:

ksh93$ /bin/sleep 10 | read
^Z

Tja, jetzt hält sie. Einen Prompt bekommt man aber nicht, intr (^C)
und quit (^\) verhallen ungehört, und der Prozess wartet bis Sankt
Nimmerlein, dass ein SIGCONT vom Himmel fällt.

PID PGID STAT COMMAND
30796 30796 S - ksh93 ksh93
31981 31981 T+p `-- /bin/sleep 10

Autsch.
--
Christian "naddy" Weisgerber ***@mips.inka.de
Ulli Horlacher
2024-05-13 15:48:25 UTC
Permalink
Post by Christian Weisgerber
Post by Ulli Horlacher
Post by Thomas Dorner
Da es nur eine Pipe ist und der Teil danach der interessante ist, kann
man sich hier mit
| shopt -s lastpipe
behelfen.
Natürlich nicht, ist ja bash-spezifisch.
Post by Ulli Horlacher
5.1.16(1)-release
Natuerlich funktioniert es nicht mit der bash? WTF?
Post by Christian Weisgerber
lastpipe
If set, and job control is not active, the shell runs
the last command of a pipeline not executed in the
background in the current shell environment.
Du hast mein Beispiel geloescht, wo ich zeige, dass es eben NICHT
funktioniert.
Post by Christian Weisgerber
In einer interaktiven Shell ist Job Control standardmäßig aktiviert,
Was hat das damit zu tun?
--
Ullrich Horlacher Server und Virtualisierung
Rechenzentrum TIK
Universitaet Stuttgart E-Mail: ***@tik.uni-stuttgart.de
Allmandring 30a Tel: ++49-711-68565868
70569 Stuttgart (Germany) WWW: https://www.tik.uni-stuttgart.de/
Thomas Dorner
2024-05-14 11:53:15 UTC
Permalink
Post by Ulli Horlacher
Post by Thomas Dorner
Post by Thomas Dorner
Da es nur eine Pipe ist und der Teil danach der interessante ist, kann
man sich hier mit
| shopt -s lastpipe
behelfen.
lastpipe
If set, and job control is not active, the shell runs
the last command of a pipeline not executed in the
background in the current shell environment.
Du hast mein Beispiel geloescht, wo ich zeige, dass es eben NICHT
funktioniert.
Post by Thomas Dorner
In einer interaktiven Shell ist Job Control standardmäßig aktiviert,
Was hat das damit zu tun?
Daß Du Dein Beispiel in einer interaktiven Shell mit aktiver Job Control
getestet hast. In einem Skript oder einer Sub-Shell funktioniert es
nämlich:

|~> (shopt -s lastpipe; x=1; echo 2 | read x; echo $x)
|2

Viele Grüße, Thomas
--
Adresse gilt nur kurzzeitig!
Ulli Horlacher
2024-05-14 12:08:50 UTC
Permalink
Post by Thomas Dorner
Post by Ulli Horlacher
Post by Thomas Dorner
Post by Thomas Dorner
Da es nur eine Pipe ist und der Teil danach der interessante ist, kann
man sich hier mit
| shopt -s lastpipe
behelfen.
lastpipe
If set, and job control is not active, the shell runs
the last command of a pipeline not executed in the
background in the current shell environment.
Du hast mein Beispiel geloescht, wo ich zeige, dass es eben NICHT
funktioniert.
Post by Thomas Dorner
In einer interaktiven Shell ist Job Control standardmäßig aktiviert,
Was hat das damit zu tun?
Daß Du Dein Beispiel in einer interaktiven Shell mit aktiver Job Control
getestet hast. In einem Skript oder einer Sub-Shell funktioniert es
|~> (shopt -s lastpipe; x=1; echo 2 | read x; echo $x)
ARGH!
Das mit "and job control is not active" hatte ich idT ueberlesen!
Das ist doch BESCHEUERT! Warum denn diese Einschraekung?
--
Ullrich Horlacher Server und Virtualisierung
Rechenzentrum TIK
Universitaet Stuttgart E-Mail: ***@tik.uni-stuttgart.de
Allmandring 30a Tel: ++49-711-68565868
70569 Stuttgart (Germany) WWW: https://www.tik.uni-stuttgart.de/
Christian Weisgerber
2024-05-14 21:13:07 UTC
Permalink
Post by Ulli Horlacher
Post by Thomas Dorner
lastpipe
If set, and job control is not active, the shell runs
the last command of a pipeline not executed in the
background in the current shell environment.
Das mit "and job control is not active" hatte ich idT ueberlesen!
Das ist doch BESCHEUERT! Warum denn diese Einschraekung?
Wie soll's denn funktionieren?

Wird eine Pipeline im Hintergrund ausgeführt (&), dann läuft der
letzte Befehl immer in einer Subshell, damit das eben unabhängig
von der Vordergrund-Shell läuft.

Wenn ich eine Pipeline im Vordergrund ausführe, dann kann ich sie
bei Job Control ja anhalten (^Z) und in den Hintergrund legen (bg).
Wie soll das jetzt funktionieren, wenn der letzte Befehl in der
Vordergrund-Shell selbst läuft? Die Shell kann vorab nicht wissen,
ob ich sowas tun werde, also muss sie den letzten Befehl immer in
einer Subshell ausführen.

Da ich zufällig weiß, dass die AT&T Korn Shell den letzten Befehl
ohne Subshell ausführt, habe ich das mal mit sowas wie

ksh93$ sleep 30 | read
^Z

ausprobiert, wie schon gepostet. Ergebnis: Der vordere Teil der
Pipeline wird mit SIGTSTP angehalten, der hintere wird in der
Vordergrund-Shell ausgeführt, die jetzt wartet, bis sie Daten lesen
kann. Alles hängt.
--
Christian "naddy" Weisgerber ***@mips.inka.de
Martin Vaeth
2024-05-12 15:00:49 UTC
Permalink
Post by Alexander Goetzenstein
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
find ./ -name *.txt -exec meinefunktion {} \;
find ./ -name *.txt -exec /bin/sh -c 'echo "$1"
if [ -f "$1" ]; then
head -n 10 "$1"
head -n 20 "$1"
fi' sh {} \;
Alexander Goetzenstein
2024-05-12 20:13:19 UTC
Permalink
Hallo,
Post by Martin Vaeth
Post by Alexander Goetzenstein
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
find ./ -name *.txt -exec meinefunktion {} \;
find ./ -name *.txt -exec /bin/sh -c 'echo "$1"
if [ -f "$1" ]; then
head -n 10 "$1"
head -n 20 "$1"
fi' sh {} \;
Danke. Auf den Gedanken war ich zwar auch schon gekommen, aber da meine
Funktion IRL rd. 200 Zeilen lang ist, war mir das zu unhandlich.
--
Gruß
Alex
Martin Vaeth
2024-05-13 05:23:53 UTC
Permalink
Post by Alexander Goetzenstein
Hallo,
Post by Martin Vaeth
Post by Alexander Goetzenstein
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
find ./ -name *.txt -exec meinefunktion {} \;
find ./ -name *.txt -exec /bin/sh -c 'echo "$1"
if [ -f "$1" ]; then
head -n 10 "$1"
head -n 20 "$1"
fi' sh {} \;
Danke. Auf den Gedanken war ich zwar auch schon gekommen, aber da meine
Funktion IRL rd. 200 Zeilen lang ist, war mir das zu unhandlich.
Das ist aber der einzige Weg in POSIX, denn "find" ist ja ein
ein neuer prozess, und damit gibt es keinen POSIX-Weg, die Funktion
dem subprozess bekannt zu machen.
Oft ist es nur eine Frage, den Code richtig zu organisieren: Du
schreibst ihn eben gleich für „find“ statt als Funktion.

Ansonsten musst Du nicht-POSIX-Wege gehen. Die bash beispielsweise
besitzt die Möglichkeit eine Funktion zu exportieren (export -f func),
so dass sie dann den Subprozessen bekannt wird. Ist halt ebenfalls
problematisch, weil die Funktion dann *nur* im Subprozess aufgerufen
wird (also keine Variablen der Parent-Shell verändern kann), und
alle weiteren ev. benötigten Dinge (weitere Funktionen, Variablen,
usw.) ebenfalls exportiert werden müssen.
Martin Vaeth
2024-05-13 05:38:34 UTC
Permalink
Post by Martin Vaeth
Ansonsten musst Du nicht-POSIX-Wege gehen. Die bash beispielsweise
besitzt die Möglichkeit eine Funktion zu exportieren (export -f func),
so dass sie dann den Subprozessen bekannt wird.
Noch besser eignet sich für solche Dinge i.d.R. zsh:
Die kann zwar keine Funktionen exportieren wie die bash (was ich
auch eher als Sicherheitsloch denn als Feature betrachte),
aber sie hat wesentlich mächtigere glob-Funktionen als die bash:
So Dinge wie die Find-Optionen -type ... u.ä. sind da problemlos
möglich. Wenn Du nicht allzu komplexe Sachen mit find machen willst,
geht das dort i.d.R. „inline“. Ansonsten musst Du halt mit einem
for-loop die „Prä-Ergebnisse“ bearbeiten.
Helmut Waitzmann
2024-05-15 19:22:59 UTC
Permalink
Post by Alexander Goetzenstein
Hallo,
in einem Script möchte ich gefundene Dateien einer Funktion
...
meinefunktion()
{
echo $1
if [ -f $1 ]; then
head -n 10 $1
tail -n 20 $1
fi
}
find ./ -name *.txt -exec meinefunktion {} \;
So funktioniert das natürlich nicht, weil meinefunktion() kein
Shellscript o.ä. ist. Wie müsste ich vorgehen, um die Funktion
für die gefundenen Dateien auszuführen?
Du müsstest „find“ ein Shell, dem man eine Kommandozeile zur
Ausführung übergibt, starten lassen, etwa


find … -exec sh -c KOMMANDOZEILE sh \{\} \;


und in der Kommandozeile „KOMMANDOZEILE“ die gewünschte
Funktion definieren und ausführen:


find … -exec sh -c '
meinefunktion()
{
printf '\''%s\n'\'' "$1"
if test -f "$1"
then
head -n 10 "$1"
tail -n 20 "$1"
fi
} &&
meinefunktion "$1"
' sh \{\} \;


Manche bezeichnen das, was da beim „printf“‐Kommando auftritt,
als „Quoting‐Hölle“.  Wenn man ein Here‐Dokument benutzt, wird
man sie los:


commandstring="$(
sed -E -e '/^[[:blank:]]*#[[:blank:]]?/s///' \
<<-\ENDE
# meinefunktion()
# {
# printf '%s\n' "$1"
# if test -f "$1"
# then
# head -n 10 "$1"
# tail -n 20 "$1"
# fi
# } &&
# meinefunktion "$1"
ENDE
)" &&
find … -exec sh -c "$commandstring" sh \{\} \;


Noch eine Anmerkung zu


sed -E -e '/^[[:blank:]]*#[[:blank:]]?/s///' \
<<-\ENDE


ist angebracht:  Wenn man nicht einfach


cat <<-\ENDE


sondern


sed -E -e '/^[[:blank:]]*#[[:blank:]]?/s///' <<-\ENDE


verwendet, kann man jede Zeile des Here‐Dokuments mit einem
Anfangsstück (hier bestehend aus null oder mehreren Tabulatoren,
einem „#“ und einem Tabulator) versehen, das sich von der Zeile
„ENDE“ von vorne herein unterscheidet und trotzdem schließlich im
an das Shell übergebenen Kommandotext nicht enthalten ist, ohne,
dass man bei der Erstellung des Here‐Dokuments extra darauf
achten muss, in keine Zeile aus Versehen „ENDE“ zu schreiben
(etwa, weil man im Here‐Dokument ein Here‐Dokument verwendet).
Loading...