Dakuan
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Vorgeschichte: Vor 2 Tagen war auf der Startseite von Wikipedia ein Artikel über die Dolly Sisters verlinkt. Ich hatte das Bild, so wie es ist, abgespeichert und den ersten Absatz als Kommentar eingefügt. Ich hatte nicht bemerkt, dass der Dateiname mit einem "-" beginnt. Eines meiner Programme bietet die Möglichkeit weitere Programme aufzurufen und damit gibt es ein Problem, wenn diese Programme auf Kommandozeilenoptionen lauern. Bei einigen Programmen kann man das Problem umgehen, indem man als letzte Option, vor dem Dateinamen "–" einfügt. Bei meinen Programmen funktioniert das jetzt und bei Hexedit auch. Aber bei Programmen wie Exiftool beiße ich auf Granit. Dort habe ich auch in der Doku nichts gefunden. In der Konsole besteht dieses Problem auch. Bei Exiftool ist das besonders nervig, weil ich damit überprüfen will, ob meine Programme richtig funktioniert haben. Wäre schön, wenn jemand eine Idee hat, was ich da machen kann (Datei umbenennen ist ja keine echte Lösung). Im Anhang mal ein Beispiel, wie der Aufruf passiert. Das wird dann mit fork() und execvp() umgesetzt.
- Bilder
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Bei mir funktioniert
problemlos.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
exiftool kann den Inhalt der Datei auch auf stdin entgegen nehmen - in der Shell sähe das z.B. so aus:
$ cat -- --test.jpg | exiftool -
ExifTool Version Number : 12.30
File Size : 0 bytes
File Modification Date/Time : 2022:01:11 20:39:13+01:00
File Access Date/Time : 2022:01:11 20:39:13+01:00
File Inode Change Date/Time : 2022:01:11 20:39:13+01:00
File Permissions : prw-------
File Type : JPEG
File Type Extension : jpg
MIME Type : image/jpeg
JFIF Version : 1.01
Resolution Unit : None
X Resolution : 1
Y Resolution : 1
Image Width : 2048
Image Height : 1151
Encoding Process : Baseline DCT, Huffman coding
Bits Per Sample : 8
Color Components : 3
Y Cb Cr Sub Sampling : YCbCr4:2:0 (2 2)
Image Size : 2048x1151
Megapixels : 2.4
Mit Python3 geht das z.B. auch leicht:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | >>> import subprocess
>>> with open('--test.jpg', 'rb') as f:
... s = subprocess.run(['exiftool', '-'], stdin=f)
...
ExifTool Version Number : 12.30
File Size : 390 KiB
File Modification Date/Time : 2022:01:11 20:38:46+01:00
File Access Date/Time : 2022:01:11 20:38:59+01:00
File Inode Change Date/Time : 2022:01:11 20:38:46+01:00
File Permissions : -rw-r--r--
File Type : JPEG
File Type Extension : jpg
MIME Type : image/jpeg
JFIF Version : 1.01
Resolution Unit : None
X Resolution : 1
Y Resolution : 1
Image Width : 2048
Image Height : 1151
Encoding Process : Baseline DCT, Huffman coding
Bits Per Sample : 8
Color Components : 3
Y Cb Cr Sub Sampling : YCbCr4:2:0 (2 2)
Image Size : 2048x1151
Megapixels : 2.4
|
Bei C(++) muss man wie es aussieht ein bisschen mit popen spielen: https://www.gnu.org/software/libc/manual/html_node/Pipe-to-a-Subprocess.html
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
user_unknown schrieb:
Bei mir funktioniert ... problemlos. Bei mir nicht:
manfred@samurai:~/Downloads$ exiftool -- -The_Dolly_Sisters-_MET_DP106353_\(cropped\).jpg
Unknown option --
manfred@samurai:~/Downloads$
Das ist dann wohl ein Versionsproblem. In der Konsole funktioniert das (mit irrsinnig langer Ausgabe):
manfred@samurai:~/Downloads$ cat -- -The_Dolly_Sisters-_MET_DP106353_\(cropped\).jpg | exiftool -
aber wenn ich das bei meinem Programm als Aufrufstring eingebe, geht das auch nicht:
xterm -hold -e cat -- %f | exiftool -
Invalid TAG name: The_Dolly_Sisters-_MET_DP106353_(cropped).jpg
Irgendwas mache ich da wohl noch falsch. @seahawk1986 Python hilft mir da jetzt auch nicht, da ich nur C und etwas C++ spreche 😉 Und von popen() hatte ich mich in diesem Zusammenhang schon verabschiedet, wegen des quotings. deswegen auch der Hinweis auf execvp(), da verbiegt mir keine Shell etwas. Aber was muss/kann ich da noch machen?
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
Die ganz allgemeine Lösung ist: | irgendein-programm ./-datei-mit-dash-vorne
|
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
In der Konsole funktioniert das. In meinem Programmaufruf jedoch nicht.
xterm -hold -e ./%f
Invalid TAG name: The_Dolly_Sisters-_MET_DP106353_(cropped).jpg
Irgendetwas läuft bei meiner Umsetzung noch schief. Da muss ich nochmal drüber nachdenken. Ist ja nicht einfach zu debuggen, da der Patient von einem anderen Programm aufgerufen wird. Ich melde mich morgen wieder.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
Dakuan schrieb: aber wenn ich das bei meinem Programm als Aufrufstring eingebe, geht das auch nicht:
xterm -hold -e cat -- %f | exiftool -
Invalid TAG name: The_Dolly_Sisters-_MET_DP106353_(cropped).jpg
Irgendwas mache ich da wohl noch falsch.
Du hast da vermutlich keine Shell-Umgebung - ohne den Code gesehen zu haben, würde ich sowas versuchen:
| xterm -hold -e sh -c 'cat -- %f | exiftool -'
|
@seahawk1986 Python hilft mir da jetzt auch nicht, da ich nur C und etwas C++ spreche 😉
Python ist halt Ideal für einen Proof of Concept in ein paar Zeilen - in C(++) dauert es oft etwas länger... Und von popen() hatte ich mich in diesem Zusammenhang schon verabschiedet, wegen des quotings. deswegen auch der Hinweis auf execvp(), da verbiegt mir keine Shell etwas. Aber was muss/kann ich da noch machen?
Hier gibt es Beispiele wie man das mit execvp macht: https://web.stanford.edu/class/archive/cs/cs110/cs110.1196/static/lectures/06-Execvp-Pipes-and-Interprocess-Communication/lecture-06-execvp-pipes-interprocess-communication.pdf rklm schrieb: Die ganz allgemeine Lösung ist: | irgendein-programm ./-datei-mit-dash-vorne
|
Aber sollte %f nicht ohnehin zu einem vollständigen Pfad expandiert werden (zumindest laut https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s07.html)? Wie ist das in dem Programm implementiert?
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
Dakuan schrieb: In der Konsole funktioniert das. In meinem Programmaufruf jedoch nicht.
xterm -hold -e ./%f
Was soll das sein? "%f" ist ja keine Shell-Variable. Wenn das ein Muster ist, das durch einen Dateinamen ersetzt wird, dann wird es ggf. schwierig, weil z.B. absolute Namen dann verunstaltet werden. In dem Fall bietet sich eher der Ansatz mit "–" an. Oder Du sorgst dafür, dass Dateinamen, die hier ersetzt werden, den Präfix "./" bekommen, sofern sie keine absoluten Pfade sind. Ich glaube, ich brauche mehr Kontext.
|
kB
Supporter, Wikiteam
Anmeldungsdatum: 4. Oktober 2007
Beiträge: 8616
Wohnort: Münster
|
Dakuan schrieb: […] ein Beispiel, wie der Aufruf passiert
Hast Du '%f' und "%f" versucht?
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Also das Voranstellen von './' sollte eigentlich immer funktionieren und die gesuchte Lösung sein. Da das in der Konsole funktioniert und nur mit meinem Programm nicht, muss ich wohl da erstmal einen Fehler suchen. rklm schrieb: Was soll das sein? "%f" ist ja keine Shell-Variable.
Ich dachte ich hätte das erwähnt. Mein aufrufendes Programm zerlegt die Kommandozeile und übergibt das dann an execvp(). Und damit habe ich mir wohl einen Designfehler eingehandelt, denn damit ist das './' ein eigener Parameter und wird nicht als Bestandteil des Dateipfades übergeben. Das aufgerufene Programm sieht dann ein zusätzliches Leerzeichen. Da muss ich mal sehen, wie ich das reparieren kann.
Oder Du sorgst dafür, dass Dateinamen, die hier ersetzt werden, den Präfix "./" bekommen, sofern sie keine absoluten Pfade sind.
Das ist möglicherweise die einfachste Lösung. Kann ich das grundsätzlich so machen oder lieber optional? Im Anhang sieht man nochmal die einzelnen Elemente, bevor der oder die Dateinamen angehängt werden.
- Bilder
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Ich habe das voranstellen von "./" zum Testen mal fest eingebaut. Es scheint sich kein Programm daran zu stören aber es hilft auch nicht immer. Bei Exiftool funktioniert es aber bei Hexedit geht es nur mit "–" vor dem Dateinamen. Ich werde das also nur als zusätzliche Option einbauen. P.s. das ist übrigens nicht der einzige merkwürdige Dateiname, der mir in letzter Zeit begegnet ist. Das Firefox Plugin "Video DownloadHelper" kann auch Dateinamen mit führendem Leerzeichen abliefern. Sorgt auch für Verwirrung.
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12822
|
Dakuan schrieb: Ich habe das voranstellen von "./" zum Testen mal fest eingebaut. Es scheint sich kein Programm daran zu stören aber es hilft auch nicht immer. Bei Exiftool funktioniert es aber bei Hexedit geht es nur mit "–" vor dem Dateinamen.
Das ist verdächtig. Was macht denn Hexedit, wenn Du einen Dateinamen, der mit "./-" anfängt, auf der Kommandozeile übergibst, ohne vorher "–" zu haben?
P.s. das ist übrigens nicht der einzige merkwürdige Dateiname, der mir in letzter Zeit begegnet ist. Das Firefox Plugin "Video DownloadHelper" kann auch Dateinamen mit führendem Leerzeichen abliefern. Sorgt auch für Verwirrung.
Ist aber völlig legal bei einem Unix-Dateisystem.
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17552
Wohnort: Berlin
|
Dakuan schrieb:
rklm schrieb: Was soll das sein? "%f" ist ja keine Shell-Variable.
Ich dachte ich hätte das erwähnt. Mein aufrufendes Programm zerlegt die Kommandozeile und übergibt das dann an execvp(). Und damit habe ich mir wohl einen Designfehler eingehandelt, denn damit ist das './' ein eigener Parameter und wird nicht als Bestandteil des Dateipfades übergeben. Das aufgerufene Programm sieht dann ein zusätzliches Leerzeichen.
Nicht ganz.
In der Shell benutzt Du Leerzeichen (in der Regel), um die einzelnen Elemente eines Kommandos,
| PROGRAMM [OPTION]... [ARGUMENT]...
|
voneinander abzugrenzen. Wenn ein Argument ein oder mehr Leerzeichen enthält, musst Du es maskieren, damit es die Shell nicht in 2 oder mehr Teile zerlegt, die das Programm als getrennte Elemente empfängt.
gibt 2 Dateien aus, file1 und file2, aber
gibt eine aus, die in der Mitte ein Blank im Namen hat. Innerhalb eines Programms, egal ob C, C++, Java, ... übergibt man aber i.d.R. ein Array (z.B. an execvp), und alle Leerzeichen müssen zum Dateinamen gehören. Wenn Du nur eine Datei "file1 file2" hast wird der erste Befehl nicht erraten, dass es um diese geht und wenn Du nur 2 Dateien hast, file1 und file2 wird der 2. Befehl, statt nach einer Datei zu suchen nicht die 2 stattdessen nehmen. Womöglich sind die 2 Programmaufrufe so beschaffen, dass Du einmal das "./" vor den Dateinamen geklebt hast, und das andere Mal "./" als weiteres Argument übergeben hast. Die empfohlene Weise, das mit c++ zu machen - ein Screenshot roch nach c++ - kenne ich nicht, aber man kann in C++ Strings verketten. Hier eine sicher nicht gute Lösung (dotslash.cc): 1
2
3
4
5
6
7
8
9
10
11
12
13 | #include <iostream>
#include <stdio.h>
using namespace std;
int main (int argc, char** argv) {
char* filename = new char[256];
sprintf (filename, "./%s", argv[1]);
cout << filename << "\n";
return 0;
}
|
Aufruf:
Ohne den Code für hexedit und exiftool zu sehen müssen wir aber raten was Du machst, und wieso es einmal nicht klappt und das andere Mal doch.
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11179
Wohnort: München
|
Mit asprintf wird automatisch genug Speicher alloziert:
| #include <iostream>
int main(int argc, char *argv[]) {
for (int arg_n=1; arg_n < argc; arg_n++) {
char *line;
asprintf(&line, "./%s\n", argv[arg_n]);
std::cout << line;
free(line);
}
}
|
Bis C++20 mit std::format verfügbar ist, geht das mit fmt bequemer (ist als libfmt(-dev) in den Paketquellen):
| #include <fmt/core.h>
int main(int argc, char *argv[]) {
for (int arg_n=1; arg_n < argc; arg_n++) {
fmt::print("./{}\n", argv[arg_n]);
}
}
|
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
@rklm Ich habe da gestern wohl zu viel auf einmal ausprobiert. Ich habe den Test gerade noch einmal wiederholt und es geht auch mit Hexedit (wenn man es richtig macht).
Ist aber völlig legal bei einem Unix-Dateisystem.
Nicht alles was legal ist ist auch immer sinnvoll. @user_unknown ... dass Du einmal das "./" vor den Dateinamen geklebt hast, und das andere Mal "./" als weiteres Argument übergeben hast.
Letzteres war die Ausgangssituation. Mein Programm erzeugt aus den Daten in der Konfiguration eine Liste der Parameter und ergänzt diese dann mit einem oder mehreren Dateinamen, die aus einer Liste kommen. Etwa so: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | void
ExtProgMan::execute( const char * cmd, const std::vector<std::string>* list ) {
...
// erstelle Parameterliste hier ...
...
own_args = args.size();
aix = 0;
switch( mode ) {
case 1: // start program for every item in list
argv = new const char * [args.size()+2]; // +1 arg +end marker
for( it = 0; it < args.size(); ++it ) // copy options
argv[aix++] = args[it];
for( it = 0; it < list->size(); ++it ) {
//argv[aix] = (*list)[it].c_str();
n_buf = "./"; // patch
n_buf += (*list)[it].c_str(); //
argv[aix] = n_buf.c_str(); //
argv[aix+1] = 0;
run_it( argv ); // fork() & execvp()
}
break;
...
|
Wahrscheinlich ist es einfacher, wenn der Aufrufer den Vorspann erzeugt. @seahawk1986 asprintf() das kannte ich noch nicht, danke.
|