Wie erkenne ich eine neue Zeile mit einer for-Schleife?

8

An verschiedenen Stellen im Internet habe ich gefunden:

\015 
\012
\x0a - hex
\n
\r

alles als Synonyme für verschiedene Zeilenumbrüche / Wagenrückläufe ...

Aber in diesem kleinen Skript kann ich nicht erkennen, wann ich auf eine neue Zeile stoße - kann mir jemand sagen, worauf ich in der if-Zeile achten soll?

#!/bin/bash

test="this is a
test"

for a in "$test"; do

        if [[ "$a" == '\012' ]] ; then
                echo "FOUND NEWLINE"
        fi

echo "$a"

done
Lolfrog
quelle
1
Ich habe eine dumme Frage. Warum müssen Sie das tun? Wenn Sie die Eingabe Zeile für Zeile lesen cat | while read line; do ...; done, wissen Sie, dass für jede Iteration ein Wagenrücklauf vorhanden war. Wenn Ihre Eingabe Dateien mit \rohne sein kann \n, transformieren Sie die Datei einfach, tr '\r' '\n'während Sie die Eingabe verarbeiten. Wenn Sie nur wissen müssen, ob mehrere Zeilen vorhanden sind : wc -l.
Nicerobot
Willkommen bei Stack Exchange. Bitte bearbeiten Sie Ihre Frage nicht auf diese Weise, da die vorhandenen Antworten dadurch bedeutungslos werden. Da Sie einen Weg gefunden haben, Ihr Problem zu lösen, können Sie ihn als alternative Antwort veröffentlichen.
Gilles 'SO - hör auf böse zu sein'
@nicerobot Wenn es überhaupt keinen Zeilenumbruch gibt, wc -lwird 0 zurückgegeben. Sie sollten das als Antwort hinzufügen
Arcege
@lolfrog die Lösung sollte nicht in der Frage sein, Sie sollten die Antwort markieren, die die Lösung hat
Arcege

Antworten:

6

Wenn Sie Zeichenfolgen direkt unter einer forSchleife verwenden, funktioniert dies pro Wort (hier bei einem Wort: der gesamte Inhalt von, $testda es in Anführungszeichen steht) und nicht pro Zeichen. Sie müssen eine whileSchleife mit readverwenden, um Buchstaben für Buchstaben zu analysieren oder um einen numerischen Parameter einzuführen, der über die Zeichenfolge iteriert.

Darüber hinaus müssen Sie bei der Verwendung readsicherstellen, dass Zeilenumbrüche und Leerzeichen nicht als Trennzeichen interpretiert werden, und readdas Lesen von jeweils einem Zeichen erzwingen .

Hier ist eine Arbeitsversion:

#!/bin/bash

test="this is a
test"

printf %s "$test" | while IFS= read -r -N 1 a; do

        if [[ "$a" == $'\n' ]] ; then
                echo "FOUND NEWLINE"
        fi

printf %s "$a"

done

Sie könnten ersetzen $'\n'mit $'\012'oder $'\x0a', da sie alle den gleichen Newline - Code darstellen. Aber es ist nicht dasselbe wie \015oder \r- dies steht für Wagenrücklauf (Rückkehr zum Zeilenanfang). Auf Linux-Systemen werden Zeilenumbrüche mit dargestellt \n, unter Windows beispielsweise durch eine Folge von \r\n. Wenn Sie eine Textdatei von Windows haben, können Sie daher Zeilenumbrüche auch durch Suchen erkennen \r.

rozcietrzewiacz
quelle
Kurz gesagt, es wandelt die zitierte Escape-Sequenz wie \nin ihre Bytedarstellung um, sodass Sie keine hässlich aussehenden, zitierten Zeilenumbrüche in Ihre Testanweisung einfügen müssen.
Rozcietrzewiacz
4

Sie können sehr einfach in Bash nach Zeilenumbrüchen in einer Variablen suchen mit:

[[ $var = *$'\n'* ]]

Ich finde es bequemer zu benutzen:

declare -r EOL=$'\n' TAB=$'\t' # at top of script
..
if [[ $var = *$EOL* ]]; then # to test (no field-splitting in [[ )
steveL
quelle
1

Ich würde vorschlagen, zu verwenden trund dann test:

if [ -n "$(tr -cd '\n\r' < datafile)" ]; then
    echo "NEWLINE FOUND"
fi

Das tr -cdentfernt alles außer den Zeilenumbrüchen / Wagenrückläufen. Wenn die Datei Zeilenumbrüche enthält, wird eine Ausgabe ausgegeben, von der der -nTest true zurückgibt .

Arcege
quelle
\rDies funktioniert nicht für Dateien, die kein s enthalten, da durch das Ersetzen von Befehlen die nachfolgenden Zeilenumbrüche entfernt werden ( "$(printf '\n\n\n\n\n')"ist die leere Zeichenfolge).
Stéphane Chazelas