ubuntuusers.de

Array einzeln auslesen funktioniert nicht

Status: Ungelöst | Ubuntu-Version: Ubuntu 16.04 (Xenial Xerus)
Antworten |

m.g.o.d

Anmeldungsdatum:
18. November 2019

Beiträge: Zähle...

Hi Zusammen,

ich habe einen ganz einfachen Bashskript Code, wo ich nicht verstehe, wieso ich das Array nicht einzeln ausgeben kann:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#! /bin/bash

cd /home/marc/Scripts 

array=$(find *.txt) #Ausgabe next.txt test.txt third.txt

for count in ${array[@]} #creating array  
do 
    echo ${count[@]} #Funktioniert!
    echo ${array[2]} #funktioniert nicht...
done

Ich kann mir mit echo

1
"${array[@]}"

den Inhalt der Suche ausgeben lassen. Aber wenn ich z.B. sage echo "${array[2]}", dann passiert nix. Auf pos.2 muss definitiv ein Suchergebnis stehen (–> third.txt). Was mache ich falsch?

Besten Gruß, Marc

Bearbeitet von ChickenLipsRfun2eat:

Forensyntax korrigiert + Codeblock

ChickenLipsRfun2eat Team-Icon

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12067

Hallo!

Zum nutzt du die Schleife nicht sinnvoll:

1
2
3
for count in $array; do 
  echo $count
done

Dann ergibt dein find kein array, bzw. nur 1 Element im Array. Du müsstest also anders vorgehen, um die Dateien als array einzulesen.

1
2
3
4
5
6
7
8
#!/bin/bash
oldIFS=$IFS
array=()
while IFS=  read -r -d $'\0'; do
    array+=("$REPLY")
done < <(find . -iname "*.txt" -print0)
IFS=$oldIFS
echo "${array[2]}"

Aber warte mal auf die Bashjungs… ich kann das auch nur so aus meinen Scripts raus zeigen ☺

m.g.o.d

(Themenstarter)

Anmeldungsdatum:
18. November 2019

Beiträge: 29

Achso das heisst die 3 Ergebniss, die find liefert, sind für das Array nur ein einziges Feld?

Dann wäre die Frage, wie ich die 3 Ergebnisse von Find ind das Array bekomme, so das jedes Ergebnis in ein seperates Feld geschrieben wird.

Puh, keine Ahnung ☹

mike1963

Anmeldungsdatum:
28. August 2018

Beiträge: 19

m.g.o.d schrieb:

Achso das heisst die 3 Ergebniss, die find liefert, sind für das Array nur ein einziges Feld?

Dann wäre die Frage, wie ich die 3 Ergebnisse von Find ind das Array bekomme, so das jedes Ergebnis in ein seperates Feld geschrieben wird.

Puh, keine Ahnung ☹

Prinzipiell geht's, indem man die gesamte find-Anweisung in eine Klammer steckt, also so:

1
2
3
4
5

array=( $(find . -type f) )       # array=$(find . -type f) speichert alles in EINE Variable
                                  # Durch die äusseren runden Klammern erzwingt man die Speicherung als Array
# Testausgabe des Arrays ...
echo "${array[*]}"

ABER: Das funktioniert NICHT, bzw. bringt falsche Ergebnisse, wenn in irgendwelchen Dateinamen Blanks vorhanden sind ...

m.g.o.d

(Themenstarter)

Anmeldungsdatum:
18. November 2019

Beiträge: 29

mike1963 schrieb:

m.g.o.d schrieb:

Achso das heisst die 3 Ergebniss, die find liefert, sind für das Array nur ein einziges Feld?

Dann wäre die Frage, wie ich die 3 Ergebnisse von Find ind das Array bekomme, so das jedes Ergebnis in ein seperates Feld geschrieben wird.

Puh, keine Ahnung ☹

Prinzipiell geht's, indem man die gesamte find-Anweisung in eine Klammer steckt, also so:

1
2
3
4
5

array=( $(find . -type f) )       # array=$(find . -type f) speichert alles in EINE Variable
                                  # Durch die äusseren runden Klammern erzwingt man die Speicherung als Array
# Testausgabe des Arrays ...
echo "${array[*]}"

ABER: Das funktioniert NICHT, bzw. bringt falsche Ergebnisse, wenn in irgendwelchen Dateinamen Blanks vorhanden sind ...

Gracias! Ich probiere es nacher gleich aus. VG

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13219

mike1963 schrieb:

ABER: Das funktioniert NICHT, bzw. bringt falsche Ergebnisse, wenn in irgendwelchen Dateinamen Blanks vorhanden sind ...

Eben! Schlauer ist folgender Ansatz, finde ich:

1
2
3
find ... -exec sh -c 'for f; do
  echo "$f found"
done' -- +

Da werden die Dateinamen auf jeden Fall korrekt übergeben.

Wenn man es mit einer while-Schleife machen will, dann so (benötigt die bash, sh kennt "-d" nicht).

1
find ... -print0 | while -rd '' f; do echo "$f"; done

Das ist im Prinzip die Lösung von ChickenLipsRfun2eat, nur umgedreht und ich speichere die Namen nicht in einem Array.

1
2
3
4
5
6
7
8
#!/bin/bash
oldIFS=$IFS
array=()
while IFS=  read -r -d $'\0'; do
    array+=("$REPLY")
done < <(find . -iname "*.txt" -print0)
IFS=$oldIFS
echo "${array[2]}"

Die Variable "oldIFS" ist überflüssig, denn Du setzt den "IFS" ja nur für read um:

1
2
3
4
5
6
7
$ foo=bar
$ echo "$foo"
bar
$ foo=123 env | fgrep foo=
foo=123
$ echo "$foo"
bar

ChickenLipsRfun2eat Team-Icon

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12067

rklm schrieb:

Die Variable "oldIFS" ist überflüssig, denn Du setzt den "IFS" ja nur für read um:

Bei IFS bin ich mir nie sicher und in meinem Ramsch-Script wird der öfter umgesetzt, deswegen habe ich es drin gelassen ☺ Aber klingt logisch, bei nur einer Verwendung.rklm schrieb:

1
2
3
find ... -exec sh -c 'for f; do
  echo "$f found"
done' -- +

Find ich prima. Das hab ich mir auch gleich mal geklaut ☺

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13219

ChickenLipsRfun2eat schrieb:

rklm schrieb:

1
2
3
find ... -exec sh -c 'for f; do
  echo "$f found"
done' -- +

Find ich prima. Das hab ich mir auch gleich mal geklaut ☺

Ich sehe gerade, da fehlt etwas Entscheidendes:

1
2
3
find ... -exec sh -c 'for f; do
  echo "$f found"
done' -- {} +

Finde den Unterschied! 😉

ChickenLipsRfun2eat Team-Icon

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12067

Der Dateiname wird nicht übergeben…

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13219

ChickenLipsRfun2eat schrieb:

Der Dateiname wird nicht übergeben…

Die Dateinamen - aber ja. Der Poster erhält 100 Gummipunkte! ☺

mike1963

Anmeldungsdatum:
28. August 2018

Beiträge: 19

rklm schrieb:

mike1963 schrieb:

ABER: Das funktioniert NICHT, bzw. bringt falsche Ergebnisse, wenn in irgendwelchen Dateinamen Blanks vorhanden sind ...

Eben! Schlauer ist folgender Ansatz, finde ich:

1
2
3
find ... -exec sh -c 'for f; do
  echo "$f found"
done' -- +

...

Ich sehe gerade, da fehlt etwas Entscheidendes:

Und genau das ist der Grund, warum ich - wenn ich mir sicher bin, dass das Script nur ich verwende und, daß in den Dateinamen die ich ansprechen möchte eben kein Space vorhanden ist - die Lösung array=( $(find . -type f) ) bevorzugen würde. ☺

Mit meinen bescheidenen Bash-Kenntnissen sehe ich bei Deinem Code nicht auf den ersten Blick, was er denn eigentlich tut - und wenn ich ihn selbst schreiben möchte, müsste ich zuerst in man-pages stöbern ...

Klar, Deiner ist sauberer und stabiler, er funktioniert auch bei Files die ein Space im Dateinamen haben, alles keine Frage - meiner hat für mich (!) aber den Vorteil, daß ich auf den ersten Blick sehe, was er tut. Da nehme ich in Kauf, dass er bei Files mit Space im Dateinamen (die zumindest bei mir ohnehin extremst selten sind) falsche Ergebnisse liefert. 😉

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11267

Wohnort: München

Eigentlich reicht da doch schon die Bash mit globstar-Option, um die *.txt Pfade in einen array zu bringen - das klappt ganz ohne Subshell und man muss sich über Whitespace in Dateinamen keine Gedanken machen:

1
2
shopt -s globstar
array=(**/*.txt)

Auch eine Schleife, die die Pfade direkt verarbeitet (und z.B. nach Dateien filtert) ist damit simpel:

1
2
3
4
5
shopt -s globstar
for f in **/*.txt
do
   [ -f "$f" ] && echo "file $f found" || continue
done 

Das ganze ist vermutlich nicht ganz so performant wie find, aber man stolpert weniger leicht über Sonderfälle.

Antworten |