#!/bin/sh
#
# Dieses Skript demonstriert, wie man eine bestimmte Menge von Dateinamen in
# ein Bash-Feld übernehmen kann, auch wenn diese Dateinamen beliebige zulässige
# Zeichen enthalten, u.a. Newlines.
#
# 15.3.2006

# Beispiel-Verzeichnis /tmp/bsp neu anlegen und dort die Dateien
#   a1
#   $'a b'
#   $'a\nb'
#   b
# erzeugen
dir=/tmp/bsp
rm -rf $dir
mkdir $dir && cd $dir && touch a1 'a b' $'a\nb' b || exit 1

# Feld "file_array" zeilenweise ausgeben
function ausgabe()
{
  local i=0
  for file in "${file_array[@]}"
  do
    echo "$((i++)) $file"
  done
}
# Wir wollen alle Dateinamen des Beispiel-Verzeichnisses, die mit "a" beginnen,
# in das Bash-Feld "file_array" übernehmen.
#
# Um beliebige Dateinamen sauber ermitteln zu können, verwenden wir das
# Kommando "find" mit der Option "-print0". Dadurch werden die Dateinamen durch
# NUL-Bytes (Dezimalwert 0) voneinander getrennt. Wir müssen also den
# Resultat-String in einzelne Wörter zerlegen, wobei das NUL-Byte als Trenner
# fungiert.
#
# IFS lässt sich hierfür leider nicht nutzen, da die Bash Strings generell
# intern mit einem NUL-Byte abschließt, so dass die Zuweisung
#  IFS=$'\000'
# dazu führt, dass die Variable IFS als leer betrachtet wird. Eine Aufspaltung
# in Wörter findet dann nicht statt.
#
# Prinzipiell könnte man "xargs" nutzen, allerdings würde "xargs" das von ihm zu
# startende Kommando bei sehr langen Argument-Listen mehrfach aufrufen, was die
# Handhabung erschwert.
#
# Um dieses Problem leichter zu lösen, verwenden wir ein kleines Python-Skript,
# das die Ausgabe von "find" einliest, am NUL-Byte in Wörter trennt und je nach
# Implementierung eine oder mehrere Zuweisungen generiert, die das Feld
# "file_array" geschlossen oder schrittweise mit den gelesenen Dateinamen
# füllen, wenn man diese Zuweisungen in der Bash mittels "eval" auswertet.
#
# Die vom Python-Skript generierte Ausgabe mit der bzw. den Feld-Zuweisungen
# übergeben wir per Kommando-Substitution als einen String an das Kommando
# "eval". Daher wird die Kommando-Substitution in Doppelapostrophe
# eingeschlossen.

# Variante 1: geschlossene Feld-Initialisierung
eval "$(find . -maxdepth 1 -name a\* -print0 | python -c "
import sys
result = 'file_array=('
for file_name in sys.stdin.read().split('\000')[:-1]:
  result += '\'' + file_name + '\' '
print result + ')'
")"

ausgabe
echo '------------------'

# Variante 2: schrittweise Feld-Initialisierung
eval "$(find . -maxdepth 1 -name a\* -print0 | python -c "
import sys
list = sys.stdin.read().split('\000')[:-1]
for i in range(len(list)):
  print 'file_array[%d]=\'%s\'' % (i, list[i])
")"

ausgabe

