2016-06-20 11 views
-1

Ich habe 2 Skripte, # 1 und # 2. Jede Arbeit von sich aus OK. Ich möchte eine 15-zeilige Datei zeilenweise lesen und verarbeiten. Skript # 2 wählt Zeilen aus. Zeile 0 ist als erste Zeile = 0, letzte Zeile = 1 angegeben. Zeile 14 wäre erste Zeile = 14, letzte Zeile = 15. Ich sehe gute Ergebnisse von echo. Ich möchte dasselbe mit Skript # 1 machen. Ich kann meinen Kopf nicht richtig herumnisten. Code unten.Wie Schlaufen korrekt verschachtelt werden

#!/bin/bash 

    # script 1 

    filename=slash 
    firstline=0 
    lastline=1 

    i=0 
    exec <${filename} 
    while read ; do 
     i=$(($i + 1)) 
     if [ "$i" -ge "${firstline}" ] ; then 
     if [ "$i" -gt "${lastline}" ] ; then 
      break 
     else 
      echo "${REPLY}" > slash1 
      fold -w 21 -s slash1 > news1 
      sleep 5 
     fi 
     fi 
    done 


    # script2 

    firstline=(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14) 
    lastline=(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) 

    for ((i=0;i<${#firstline[@]};i++)) 
    do 
     echo ${firstline[$i]} ${lastline[$i]}; 
    done 
+1

Eine Randnotiz, könnten Sie ersetzen 'i = $ (($ i + 1))' mit '((i ++))'. – sjsam

+2

Im Nachhinein ist dies ein [XY-Problem] (http://meta.stackexchange.com/a/66378/248777): Das Problem wird besser mit einer einzigen Schleife gelöst, die ein externes Dienstprogramm verwendet, um die interessierende Linie zu extrahieren Zeilennummer - keine Notwendigkeit für eine _nested_ Schleife. – mklement0

Antwort

1

Ihre Frage ist sehr unklar, aber vielleicht sind Sie einfach für einige einfache Funktion sucht Anrufe:

#!/bin/bash 

script_1() { 

    filename=slash 
    firstline=$1 
    lastline=$2 

    i=0 
    exec <${filename} 
    while read ; do 
     i=$(($i + 1)) 
     if [ "$i" -ge "${firstline}" ] ; then 
     if [ "$i" -gt "${lastline}" ] ; then 
      break 
     else 
      echo "${REPLY}" > slash1 
      fold -w 21 -s slash1 > news1 
      sleep 5 
     fi 
     fi 
    done 
} 


    # script2 

    firstline=(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14) 
    lastline=(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) 

    for ((i=0;i<${#firstline[@]};i++)) 
    do 
     script_1 ${firstline[$i]} ${lastline[$i]}; 
    done 

Beachten Sie, dass die Datei auf diese Weise das Lesen extrem ineffizient ist, und es gibt zweifellos bessere Möglichkeiten zu Handle das, aber ich versuche, die Änderungen von Ihrem Code zu minimieren.

+0

Ich werde den Code versuchen, den Sie zeigen. Ich möchte 15 verschiedene Nachrichtenüberschriften sehen, einzeln für 5 Sekunden in den Nachrichten1. Nach 5 Sekunden wird der Bildschirm ausgeblendet und die nächste Überschrift angezeigt. Die Ausblendung erfolgt und vieles mehr in einem Python-Skript. Die Anzeige einer einzigen Überschrift funktioniert bereits und wird alle 5 Minuten aktualisiert. – donde

1

aktualisieren: Basierend auf Ihren späteren Kommentaren, der folgende idiomatische Bash-Code, der sed die Linie von Interesse in jeder Iteration zu extrahieren verwendet löst Ihr Problem viel einfacher:

Hinweis:
- Wenn die Die Eingabedatei ändert sich nicht zwischen Schleifeniterationen, und die Eingabedatei ist klein genug (wie es im vorliegenden Fall der Fall ist), es ist effizienter, den Dateiinhalt in einer Variablen im Voraus zu puffern, wie in der ursprünglichen Antwort unten gezeigt.
- As tripleee Punkte in einem Kommentar aus: Wenn nur die Linien Eingangs Lesen sequentiell ausreichend ist (wie durch spezifischen Zeilennummern Extrahieren Linien entgegengesetzt, dann wird eine einzige, einfache while read -r line; do ... # fold and output, then sleep ... done < "$filename" genug ist

# Determine the input filename. 
filename='slash' 

# Count its number of lines. 
lineCount=$(wc -l < "$filename") 

# Loop over the line numbers of the file. 
for ((lineNum = 1; lineNum <= lineCount; ++lineNum)); do 
    # Use `sed` to extract the line with the line number at hand, 
    # reformat it, and output to the target file. 
    fold -w 21 -s <(sed -n "$lineNum {p;q;}" "$filename") > 'news1' 
    sleep 5 
done 
.

Eine vereinfachte Version von dem, was ich denke, Sie erreichen wollen:

#!/bin/bash 

# Split fields by newlines on input, 
# and separate array items by newlines on output. 
IFS=$'\n' 

# Read all input lines up front, into array ${lines[@]} 
# In terms of your code, you'd use 
# read -d '' -ra lines < "$filename" 
read -d '' -ra lines <<<$'line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10\nline 11\nline 12\nline 13\nline 14\nline 15' 

# Define the arrays specifying the line ranges to select. 
firstline=(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14) 
lastline=(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) 

# Loop over the ranges and select a range of lines in each iteration. 
for ((i=0; i<${#firstline[@]}; i++)); do 
    extractedLines="${lines[*]: ${firstline[i]}: 1 + ${lastline[i]} - ${firstline[i]}}" 
    # Process the extracted lines. 
    # In terms of your code, the `> slash1` and `fold ...` commands would go here. 
    echo "$extractedLines" 
    echo '------' 
done 

Anmerkung:

  • Der Name der Arrayvariablen gefüllt mit read -ralines ist; ${lines[@]} ist Bash Syntax alle Arrayelemente als separate Wörter (${lines[*]} bezieht sich auch auf alle Elemente, aber mit leicht unterschiedlichen Semantik) zum Zurückführen, und diese Syntax in den Kommentaren verwendet wird, zu veranschaulichen, dass lines ist in der Tat ein Array Variable (note dass, wenn Sie einfach $lines verwenden waren die Variable zu verweisen, Sie implizit nur das Element mit dem Index 0 bekommen würde, die gleich wie:. ${lines[0]}

  • <<<$'line 1\n...' verwendet eine here-string (<<<) eine Ad- zu lesen hoc Beispiel Dokument (ausgedrückt als ein ANSI C-quoted string ($'...')) im Interesse der mein Beispiel Code in sich abgeschlossen.

    • Wie im Kommentar angegeben, dann würden Sie von $filename statt lesen:
      read -d '' -ra lines <"$filename"
  • extractedLines="${lines[*]: ${firstline[i]}: 1 + ${lastline[i]} - ${firstline[i]}}" die Linien von Interesse extrahiert; ${firstline[i]} referenziert das aktuelle Element (Index i) von Array ${firstline[@]}; da das letzte Token in heftiger Schlag des Array-Slicing-Syntax
    (${lines[*]: <startIndex>: <elementCount>}) die Zählung der Elemente zurückkehren, müssen wir eine Berechnung durchführen die Zählung, um zu bestimmen, das ist, was 1 + ${lastline[i]} - ${firstline[i]} tut.

    • Durch "${lines[*]...}" Verwendung anstatt "${lines[@]...}", die extrahierten Feldelemente von dem ersten Zeichen in $IFS verbunden sind, die in unserem Fall eine Neue-Zeile ist ($'\n') (wenn eine einzige Linie Extrahieren doesn dass‘ t wirklich wichtig).
+0

Lesen Sie alle Eingangszeilen vor, in Array $ {Zeilen [@]}? Nicht sicher, was "@" bedeutet. Wo ist $ filename in der Leseleitung? – donde

+0

@Donde: Siehe mein Update; Ich schlage vor, dass Sie sich mit [Funktionsweise von Arrays in Bash] vertraut machen (https://www.gnu.org/software/bash/manual/html_node/Arrays.html). – mklement0

+0

Uh, die Eingabedatei erneut zu lesen, um eine einzelne Zeile innerhalb der Schleife zu extrahieren, ist ein riesiges Antipattern. Lies einfach die Zeilen. – tripleee

Verwandte Themen