ubuntuusers.de

Bash-Skript Variable mit Dateinamen und Leerzeichen an Programm als Argument übergeben

Status: Ungelöst | Ubuntu-Version: Ubuntu 14.04 (Trusty Tahr)
Antworten |

J-K

Anmeldungsdatum:
21. August 2007

Beiträge: 49

Wohnort: Bebra

Hallo,

ich habe mich schon durchs Forum gewühlt, komme aber gerade nicht weiter. Problem sind wie so oft die Leerzeichen in Dateinamen. ☹

Ich habe beispielhaft folgendes Programm:

 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
26
27
28
29
30
31
32
33
34
#!/bin/bash -xf
bereich="A1-2 B3-5"
output_filename_tmp="/tmp/extracted.pdf"
i=0
	STRING=""
	chars=( {A..Z} )
	
	for file in "$@"; do 
		if [ -n "$file" ]
		then
		
			STRING=$STRING${chars[i]}=${file// /\\ }" "
			#STRING=$STRING${chars[i]}='"'$file'" '	
			#STRING="$STRING"${chars[i]}="'"${file}"' "
			#STRING=$STRING${chars[i]}='"'${file// /∑}'" '		
			#STRING=$STRING${chars[i]}='"'${file// /\\ }'" '		
			else
				true
		fi
		
	 	let "i+=1"
	done
	
	echo
	echo $STRING
	echo "$STRING"
	echo
	

# Syntax: pdftk A=/Pfad/zur/PDF-Datei1 B=/Pfad/zur/PDF-Datei cat A1-2 B3-5 output Neu.pdf

#	pdftk ${STRING//∑/ } cat $bereich output "$output_filename_tmp"
	pdftk $STRING cat $bereich output "$output_filename_tmp"
	pdftk "$STRING" cat $bereich output "$output_filename_tmp"

Ich rufe es beispielsweise folgendermaßen auf:

~/bin/bash-test '/tmp/name.pdf' '/tmp/Datei Name.pdf'

Was beim zweiten echo-Befehl noch gut aussieht, funktioniert bei der Ausführung mit pdftk schon nicht mehr, da der ganze String als ein Dateiname aufgefasst wird. Und wenn die Variable wie in Zeile 26 nicht in Anführungszeichen eingeschlossen wird, dann sieht die Ausgabe (durch #!/bin/bash -xf) so aus:

+ echo /tmp/name.pdf '/tmp/Datei\' Name.pdf

Wie an den auskommentierten Zeilen zu sehen, habe ich schon vieles verschiedene ausprobiert, aber leider hat nix bisher funktioniert.

Ich vermute, ich müsste die einfachen Hochkommata zum Escapen in Zeile 12 verwenden, aber ich schaffe es nicht, diese in den String zu bringen.

Woran liegt das? Wo ist mein Denkfehler? Ich freue mich über jeden Hinweis!

Vielen Dank, J-K

PS:

Wer neugierig ist, ich habe ein Skript geschrieben, dass aus Nautilus heraus aufgerufen wird und mit zenity eine grafische Oberfläche bietet um aus einer oder mehreren PDF-Dateien bestimmte Seiten mit pdftk zu einer Datei zusammenzustellen. Bei Interesse poste ich gerne den ganzen Code.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Also, die Zeile 12 bei Dir sieht ja schon sehr seltsam aus ...

Was willst Du damit erreichen ? - beschreib es doch mal in Prosa, mit einem Beispiel. Denn so eine doppelte "="- Zuweisung, noch dazu ungequotet, kann ja überhaupt nicht funktionieren.

Gib doch bitte mal ein Beispiel, wie der Dateiname vorher → nachher aussehen soll.
(es ist immer blöd, wenn man anhand Deines Codes raten muss, was Du überhaupt erreichen willst)

track

J-K

(Themenstarter)

Anmeldungsdatum:
21. August 2007

Beiträge: 49

Wohnort: Bebra

Hallo track,

vorneweg: Ich kann meinen Beitrag leider nicht mehr bearbeiten, und mir fiel gerade ein Tippfehler auf: J-K schrieb:

Und wenn die Variable wie in Zeile 26 nicht in Anführungszeichen eingeschlossen wird,

Es muss richtig „wie in Zeile 25“ heißen.

Beim letzten Versuch (Zeile 12) war ich wohl schon so müde, dass mir die fehlenden Anführungszeichen ums = nicht aufgefallen sind…

Entschuldigung, dass ich es nicht nochmal dazu geschrieben hatte, das Syntax-Beispiel in Zeile 30 sollte mein Ziel zeigen:

1
pdftk A=/Pfad/zur/PDF-Datei1 B=/Pfad/zur/PDF-Datei cat A1-2 B3-5 output Neu.pdf

Also, ich möchte die einzelnen Dateinamen mit Buchstaben gefolgt von einem Gleichheitszeichen hintereinander reihen, getrennt durch ein Leerzeichen. Das Problem ist das Escapen der Leerzeichen in Dateinamen, so dass die Variable richtig an pdftk übergeben wird.

Wenn ich es direkt in der bash schreibe, funktionieren folgende Zeilen

1
2
3
pdftk A=/tmp/name.pdf B=/tmp/Datei\ Name.pdf cat A1-2 B3-5 output Neu.pdf
pdftk A=/tmp/name.pdf B="/tmp/Datei Name.pdf" cat A1-2 B3-5 output Neu.pdf
pdftk A=/tmp/name.pdf B='/tmp/Datei Name.pdf' cat A1-2 B3-5 output Neu.pdf

Mischungen mit escap(e)tem Leerzeichen und Anführungszeichen funktionieren nicht.

Ich hoffe, ich konnte mich verständlich ausdrücken. Falls nicht, frag bitte einfach nochmal noch nach. ☺

Vielen Dank, J-K

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17605

Wohnort: Berlin

Ich glaube alles was Du brauchst ist dies:

1
pdftk A="$1" B="$2" cat A1-2 B3-5 output neu.pdf

Erst $1 und $2 zeichenweise zerlegen mit deklaration der Zeichenklasse... - da würde man ja nie ein Script fertig bekommen.

J-K

(Themenstarter)

Anmeldungsdatum:
21. August 2007

Beiträge: 49

Wohnort: Bebra

Mh, ich weiß doch vorher aber gar nicht, wie viele Dateien übergeben werden. Deshalb habe ich ja versucht diesen Text

A="$1" B="$2"

mit der for-Schleife zu erzeugen und in eine Variable $STRING zu schreiben.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17605

Wohnort: Berlin

Ich kenne pdftk nicht, und dachte anhand von

1
bereich="A1-2 B3-5"

, dass es 2 Dateien gäbe, eine mit A und eine mit B codiert.

Du beschreibst ja nirgends, was Dein Programm tun soll und die Beispiele zeigen jeweils 2 Dateien.

"String" und "chars" sind auch mit die übelsten Variablennamen, die man sich ausdenken kann, wenn man da von ausdenken überhaupt reden will. Ist ja mehr eine Ausdenkverweigerung.

Es gibt nur 3 ernsthafte Probleme beim Programmieren:

  • Off-by-one-Fehler (Schleife läuft einmal zu oft o. zu selten u.s.ä.)

  • Naming things (gute Bezeichner, die einem auch in 6 Monaten schlagartig klarmachen, was gemeint ist).

J-K

(Themenstarter)

Anmeldungsdatum:
21. August 2007

Beiträge: 49

Wohnort: Bebra

Da hast Du recht, $STRING war eine Ausdenkverweigerung. Ich hoffe, $filenames_with_handles ist klarer.

Hier folgt der ganze Code:

 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#!/bin/bash -xf

ZENITY=$(which zenity)
TITLE="PDF: Seiten extrahieren"
E_BADARGS=85


if [ ! -n "$1" ]
then
  echo "Usage: `basename $0` file1 file2 etc."
  exit $E_BADARGS
  elif [ $# -gt 26 ]
  		then
  		$ZENITY --error $TITLE --text="Derzeit sind nur maximal 26 Eingabe-Dateien möglich! (A-Z)"
    exit $E_BADARGS
fi  

firstfile="$1"

if [ $# -gt 1 ]
then
	i=0
	filenames_with_handles=""
	filenames_with_handles_formatiert=""
	chars=( {A..Z} )
	
	for file in "$@"; do 
		if [ -n "$file" ]
		then
		
			#filenames_with_handles=$filenames_with_handles${chars[i]}'="'${file// /\\ }'" '
			filenames_with_handles=$filenames_with_handles${chars[i]}'='${file// /\\ }' '
			filenames_with_handles_formatiert=$filenames_with_handles_formatiert${chars[i]}='"'$file'" 
			'
			else
				true
		fi
		
	 	let "i+=1"
	done
else
	filenames_with_handles="$firstfile"
	filenames_with_handles_formatiert="$firstfile"
fi

bereich=$($ZENITY --entry --title="$TITLE" --text="Welcher Seiten-Bereich soll extrahiert werden? 
Angabe im pdftk-Format

$filenames_with_handles_formatiert")

if [ "$?" = 1 ] ; then
        exit 1;
fi

dir=${firstfile%/*}
filename=${firstfile##*/}
suggested_filename=$dir/extracted-"$filename"
output_filename=$($ZENITY --file-selection --save --confirm-overwrite --filename="$suggested_filename" --title="$TITLE"": Ausgabe-Datei")
if [ "$?" = 1 ] ; then
        exit 1;
fi

output_filename_tmp=$output_filename".tmp"

pdftk $filenames_with_handles cat $bereich output "$output_filename_tmp"

#PDF-Metadaten der (ersten Datei) übertragen
pdftk $firstfile dump_data_utf8 output | grep Info | pdftk "$output_filename_tmp"  update_info_utf8 - output "$output_filename"
rm "$output_filename_tmp"

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Was Du im Grunde suchst, ist ein Array, in dem die "gequoteten" Sachen alle stehen:

track@track:~$ var=( "erster Parameter" "zweiter      Parameter" "dritter Parameter
sogar mit Zeilenumbruch" )
track@track:~$ echo "${var[@]}"
erster Parameter zweiter      Parameter dritter Parameter
sogar mit Zeilenumbruch
track@track:~$ echo 1. "${var[0]}"
1. erster Parameter
track@track:~$ echo 2. "${var[1]}"
2. zweiter      Parameter
track@track:~$ echo 3. "${var[2]}"
3. dritter Parameter
sogar mit Zeilenumbruch 

Wenn Du willst, kannst Du in der Schleife mit var+= beliebig weitere Array-Zellen anhängen.

Im Übrigen solltest Du lieber konsequent bei $kleinen Variablennamen bleiben, denn die sind ausdrücklich für User-Variablen reserviert.
$GROSS sind Systemvariablen, und wenn Du Pech hast, schreibst Du eine davon kaputt ... 😉

LG,

track

J-K

(Themenstarter)

Anmeldungsdatum:
21. August 2007

Beiträge: 49

Wohnort: Bebra

@track: Vielen Dank, mit einem Array ging es dann tatsächlich!

Ich musste nur die Variable nochmal quoten:

1
filenames_with_handles+=(${chars[i]}'='"$file")

Hier nun der funktionierende, vollständige Code:

 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/bin/bash
# GUI für pdftk-Seiten extrahieren - vorrangig für Aufruf aus Dateibrowser heraus

zenity=$(which zenity)
titel="PDF: Seiten extrahieren"
error_badargs=85


if [ ! -n "$1" ]
then
  echo "Usage: `basename $0` datei1 datei2 etc."
  exit $error_badargs
  elif [ $# -gt 26 ]
  		then
  		$zenity --error $titel --text="Derzeit sind nur maximal 26 Eingabe-Dateien möglich! (A-Z)"
    exit $error_badargs
fi  

firstfile="$1"

if [ $# -gt 1 ]
then
	i=0
	filenames_with_handles=()
	filenames_with_handles_formatiert=""
	chars=( {A..Z} )
	
	for file in "$@"; do 
		if [ -n "$file" ]
		then
			filenames_with_handles+=(${chars[i]}'='"$file")		
			filenames_with_handles_formatiert+=${chars[i]}'='"$file"' 
'
		fi
		
	 	let "i+=1"
	done
else
	filenames_with_handles+="$firstfile"
	filenames_with_handles_formatiert="$firstfile"
fi

bereich=$($zenity --entry --title="$titel" --text="Welcher Seiten-Bereich soll extrahiert werden? 
Angabe im pdftk-Format

$filenames_with_handles_formatiert")

if [ "$?" = 1 ] ; then
        exit 1;
fi

dir=${firstfile%/*}
filename=${firstfile##*/}
suggested_filename=$dir/extracted-"$filename"
output_filename=$($zenity --file-selection --save --confirm-overwrite --filename="$suggested_filename" --title="$titel"": Ausgabe-Datei")
if [ "$?" = 1 ] ; then
        exit 1;
fi

output_filename_tmp=$output_filename".tmp"
log=$output_filename".log"

pdftk "${filenames_with_handles[@]}" cat $bereich output "$output_filename_tmp" 2>"$log" 

if [ "$?" = 0 ] 
then
       
#PDF-Metadaten der (ersten Datei) übertragen
pdftk "$firstfile" dump_data_utf8 output | grep Info | pdftk "$output_filename_tmp"  update_info_utf8 - output "$output_filename" 2>"$log" && rm "$output_filename_tmp"

fi

if [ -s "$log" ]
then
	zenity --text-info --title "Fehler!" --filename="$log"  --width 600 --height 300 
 elif [ -e "$log" ]
 	then
		rm "$log"
fi
Antworten |