Comment découvrir une nouvelle ligne en utilisant une boucle for?

8

Dans divers endroits du Web, j'ai trouvé:

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

tous comme synonymes de divers retours à la ligne / retours chariot ...

Mais dans ce petit script, je ne peux pas reconnaître quand je tombe sur une nouvelle ligne - quelqu'un peut-il me dire ce que je devrais vérifier dans la ligne if?

#!/bin/bash

test="this is a
test"

for a in "$test"; do

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

echo "$a"

done
lolfrog
la source
1
J'ai une question stupide. Pourquoi avez-vous besoin de faire ça? Si vous lisez l'entrée ligne par ligne cat | while read line; do ...; done, vous savez qu'il y a eu un retour chariot pour chaque itération. Si votre entrée peut être des fichiers \rsans \n, il suffit de transformer le fichier tr '\r' '\n'lors du traitement de l'entrée. Si vous avez juste besoin de savoir s'il y a plusieurs lignes: wc -l.
nicerobot
Bienvenue sur Stack Exchange. Veuillez ne pas modifier votre question de cette façon, car cela rend les réponses existantes dénuées de sens. Puisque vous avez trouvé un moyen de résoudre votre problème, vous pouvez le poster en tant que réponse alternative.
Gilles 'SO- arrête d'être méchant'
@nicerobot s'il n'y a pas de nouvelle ligne, alors wc -lretournera 0; vous devriez ajouter cela comme une réponse
Arcege
@lolfrog la solution ne devrait pas être dans la question, vous devez cocher la réponse qui a la solution
Arcege

Réponses:

6

Si vous utilisez directement des chaînes sous une forboucle, cela fonctionnera par mot (ici sur un mot: tout le contenu de $testdepuis qu'il est cité), pas par caractère. Vous devez utiliser une whileboucle avec readpour analyser lettre par lettre, ou pour introduire un paramètre numérique qui itérerait sur la chaîne.

De plus, lors de l'utilisation read, vous devez vous assurer que les sauts de ligne et les espaces ne sont pas interprétés comme des délimiteurs et forcer readà lire un caractère à la fois.

Voici une version de travail:

#!/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

Vous pouvez remplacer $'\n'par $'\012'ou $'\x0a', car ils représentent tous le même code de nouvelle ligne. Mais ce n'est pas la même chose que \015ou \r- cela signifie retour chariot (retour au début de la ligne). Sur les systèmes Linux, les sauts de ligne sont représentés à l'aide \n, mais sur Windows par exemple, ils sont représentés par une séquence de à la \r\nplace. C'est pourquoi si vous aviez un fichier texte de Windows, vous pouvez également détecter les sauts de ligne en recherchant \r.

rozcietrzewiacz
la source
En bref, il transforme la séquence d'échappement entre guillemets \nen sa représentation d'octets, de sorte que vous n'avez pas besoin de placer des sauts de ligne entre guillemets dans votre instruction de test.
rozcietrzewiacz
4

Vous pouvez vérifier très facilement les sauts de ligne dans une variable en bash avec:

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

Je le trouve plus pratique à utiliser:

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

Je suggère d'utiliser trpuis test:

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

Le tr -cdsupprime tout sauf les retours à la ligne / retours chariot. S'il y a des sauts de ligne dans le fichier, alors il y aura une sortie à partir de laquelle le -ntest retournera vrai.

Arcege
la source
Cela ne fonctionnera pas pour les fichiers ne contenant pas de \rs car la substitution de commande supprime les caractères de fin de ligne ( "$(printf '\n\n\n\n\n')"c'est la chaîne vide).
Stéphane Chazelas