Frage

Ich versuche, durch ein Verzeichnis von Textdateien in einer Schleife und kombinieren sie in einem Dokument. Dies funktioniert gut, aber die Textdateien enthalten Code-Schnipsel, und alle meine Formatierung wird immer auf der linken Seite zusammenbrach. Alle führenden Leerzeichen auf einer Linie abgezogen wird.

#!/bin/sh
OUTPUT="../best_practices.textile"
FILES="../best-practices/*.textile"
for f in "$FILES"
do
  echo "Processing $f file..."
  echo "">$OUTPUT

  cat $f | while read line; do 
      echo "$line">>$OUTPUT
  done
  echo >>$OUTPUT
  echo >>$OUTPUT
done

Ich bin zugegebenermaßen ein bash noob, aber nach hohen und niedrigen Suche konnte ich nicht eine richtige Lösung finden. Offenbar BASH Leeraums im Allgemeinen hasst.

War es hilfreich?

Lösung

Statt:

cat $f | while read line; do 
    echo "$line">>$OUTPUT
done

Tun Sie dies:

cat $f >>$OUTPUT

(Wenn es ein Grund, warum Sie brauchen, um Dinge Zeile für Zeile zu tun, es wäre gut, dass in der Frage einzubeziehen.)

Andere Tipps

Wie andere haben darauf hingewiesen, mit Katze oder awk anstelle einer Lese-Echo-Schleife ist ein viel besserer Weg, dies zu tun - vermeidet das Leerzeichen-Trimmen Problem (und ein paar andere, die Sie auf nicht gestolpert), läuft schneller, und zumindest mit Katze, ist einfach sauberer Code. Dennoch möchte ich einen Stich nehmen auf die Lese-Echo-Schleife immer richtig zu arbeiten.

Zuerst wird das durch Leerzeichen Trimmen Problem: der Lesebefehl automatisch trimmt führende und nachfolgende Leerzeichen; Dies kann durch Einstellen der IFS Variable Rohling durch Änderung seiner Definition von Leerzeichen fixiert werden. Auch las davon ausgeht, dass ein umgekehrter Schrägstrich am Ende der Zeile die nächste Zeile bedeutet eine Fortsetzung ist, und sollte mit diesem zusammen gespleißt werden; Um dies zu beheben, seine -r (raw) Flag verwenden. Das dritte Problem ist, dass viele Implementierungen von Echo Escape-Sequenzen in der Zeichenkette interpretieren (z.B. können sie \ n drehen in eine tatsächliche Neuen-Zeile); Verwenden Sie hierzu printf stattdessen zu beheben. Schließlich nur als allgemeine Scripting Hygiene Regel sollten Sie nicht Katze verwenden, wenn Sie eigentlich nicht brauchen; anstelle Eingabeumleitung. Mit diesen Änderungen sieht die innere Schleife wie folgt aus:

while IFS='' read -r line; do 
  printf "%s\n" "$line">>$OUTPUT
done <$f

... es gibt auch ein paar andere Probleme mit dem umgebenden Skript: die Linie, die Dateien als auch die Liste der verfügbaren Dateien .textile hat Anführungszeichen um es zu definieren versucht, was bedeutet, es nie in eine aktuelle Liste von Dateien erweitert wird . Der beste Weg, dies zu tun ist, um ein Array zu verwenden:

FILES=(../best-practices/*.textile)
...
for f in "${FILES[@]}"

(und alle Vorkommen von $ f in doppelten Anführungszeichen in Fall sein, wenn eine der Dateinamen haben Leerzeichen oder andere lustige Figuren in ihnen - wirklich dies auch mit $ OUTPUT tun soll, aber da, dass im Skript definiert ist, ist es tatsächlich sicher wegzulassen.)

Schließlich gibt es noch einen echo "">$OUTPUT in der Nähe der Spitze der Schleife-over-Dateien, die die Ausgabedatei jedes Mal durch löschen gehen (das heißt am Ende, nur die letzte .textile Datei enthält); muss diese vor der Schleife zu bewegen. Ich bin mir nicht sicher, ob es die Absicht, hier war eine einzige Leerzeile am Anfang der Datei zu setzen, oder drei Leerzeilen zwischen Dateien (und einem am Anfang und zwei am Ende), so dass ich bin mir nicht sicher, was genau der entsprechende Ersatz ist. Wie auch immer, hier ist das, was ich kann, bis mit nach all diesen Problemen Festsetzung:

#!/bin/sh
OUTPUT="../best_practices.textile"
FILES=(../best-practices/*.textile)

: >"$OUTPUT"
for f in "${FILES[@]}"
do
  echo "Processing $f file..."
  echo >>"$OUTPUT"

  while IFS='' read -r line; do 
    printf "%s\n" "$line">>"$OUTPUT"
  done <"$f"

  echo >>"$OUTPUT"
  echo >>"$OUTPUT"
done

das ist eine zu teure Art und Weise Dateien zu kombinieren.

cat ../best-practices/*.textile >  ../best_practices.textile

Wenn Sie wollen jede Datei ein Leerzeichen (Newline) hinzufügen, wie Sie verketten, verwenden awk

awk 'FNR==1{print "">"out.txt"}{print > "out.txt" }' *.textile

oder

awk 'FNR==1{print ""}{print}' file* > out.txt

Auf diese Weise können Sie Zeilenumbrüche zwischen den einzelnen Eingabedatei einzustreuen, wie Sie in Ihrem ursprünglichen Skript getan haben:

for f in $FILES; do echo -ne '\n\n' | cat "$f" -; done > $OUTPUT

Beachten Sie, dass $FILES unquoted ist für diese (sonst die zusätzlichen Zeilenumbrüche am Ende aller Ausgabe nur einmal vorkommen) zu arbeiten, aber $f müssen schützen Leerzeichen in Dateinamen angegeben werden, wenn sie vorhanden ist.

Die richtige Antwort, imo, ist diese , reproduziert unter:

while IFS= read line; do
    check=${line:0:1}
done < file.txt

Beachten Sie, dass sie kümmert sich der Situationen nehmen werde, wo der Eingang von einem anderen Befehl geleitet wird, und zwar nicht nur von einer tatsächlichen Datei.

Beachten Sie, dass Sie auch die Umleitung vereinfachen, wie unten gezeigt.

#!/bin/bash
OUTPUT="../best_practices.textile"
FILES="../best-practices/*.textile"
for f in "$FILES"
do
  echo "Processing $f file..."
  {
  echo

  while IFS= read line; do 
      echo "$line"
  done < $f
  echo
  echo;
  } > $OUTPUT
done
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top