web-dev-qa-db-fra.com

Insérer une nouvelle ligne (\ n) à l'aide de sed

J'essaie de balayer certaines listes dans un fichier CSV correctement formaté pour l'importation de base de données.

Mon fichier de départ ressemble à ceci avec ce qui est supposé être chaque "ligne" couvrant plusieurs lignes comme ci-dessous

Mr. John Doe
Exclusively Stuff, 186 
Caravelle Drive, Ponte Vedra
33487. 

J'ai créé un script sed qui nettoie le fichier (il y a beaucoup de mises en forme "sales" comme les doubles espaces et les espaces avant/après les virgules). Le problème est le zip avec la période. Je voudrais changer cette période pour une nouvelle ligne, mais je ne parviens pas à la faire fonctionner.

La commande que j'utilise est la suivante:

sed -E -f scrub.sed test.txt

et le scrub.sed Le script est le suivant:

:a
N
s|[[:space:]][[:space:]]| |g
s|,[[:space:]]|,|g
s|[[:space:]],|,|g
s|\n| |g
s|[[:space:]]([0-9]{5})\.|,FL,\1\n |g
$!ba

Ce que je reçois c'est

Mr. John Doe,Exclusively Stuff,186 Caravelle Drive,Ponte Vedra,FL,33487n 

Si figuré que le Zip +. (Point) serait un grand "délimiteur" pour utiliser la substitution sur et pendant que je peux le trouver, je ne peux pas sembler lui dire de mettre une nouvelle ligne.

La plupart des choses que j'ai trouvées en ligne concernent le remplacement de la nouvelle ligne par quelque chose d'autre (généralement leur suppression), mais pas grand chose sur le remplacement par une nouvelle ligne. J'ai trouvé ceci, mais cela n'a pas fonctionné: Comment insérer un caractère de nouvelle ligne après une virgule dans `), (` avec sed?

Y a-t-il quelque chose qui me manque?

Mise à jour:

J'ai édité mon fichier scrub.sed en insérant la nouvelle ligne littérale. Ça ne marche toujours pas

:a
N
s|[[:space:]][[:space:]]| |g
s|,[[:space:]]|,|g
s|[[:space:]],|,|g
s|\n| |g
s|[[:space:]]([0-9]{5})\.|,FL,\1\
|g
$!ba

Ce que je reçois est (tout sur une seule ligne):

Mr. John Doe,Exclusively Stuff,186 Caravelle Drive,Ponte Vedra,FL,33487 Mrs. Jane Smith,Props and Stuff,123 Main Drive,Jacksonville,FL,336907  

Ma sortie attendue devrait être:

Mr. John Doe,Exclusively Stuff,186 Caravelle Drive,Ponte Vedra,FL,33487
Mrs. Jane Smith,Props and Stuff,123 Main Drive,Jacksonville,FL,336907  
12
Allan

Le sed sur BSD ne supporte pas le \n représentation d'une nouvelle ligne (en la transformant en un littéral n):

$ echo "123." | sed -E 's/([[:digit:]]*)\./\1\n next line/'
123n next line

GNU sed supporte le \n représentation:

$ echo "123." | gsed -E 's/([[:digit:]]*)\./\1\nnext line/'
123
next line

Les alternatives sont:

Utilisez un séparateur de caractères que vous utiliserez ensuite tr traduire en une nouvelle ligne:

$ echo "123." | sed -E 's/([[:digit:]]*)\./\1|next line/' | tr '|' '\n'
123
next line

Ou utilisez une nouvelle ligne littérale échappée dans votre script sed:

$ echo "123." | sed -E 's/([[:digit:]]*)\./\1\
next line/'
123
next line

Ou utilisez awk:

$ echo "123." | awk '/^[[:digit:]]+\./{sub(/\./,"\nnext line")} 1'
123
next line

Ou utilisez GNU sed qui supporte \n

31
dawg

La méthode portable pour obtenir une nouvelle ligne dans sed est une barre oblique inverse suivie d'une nouvelle ligne:

$ echo 'foo' | sed 's/foo/foo\
bar/'
foo
bar

Je vous garantis qu'il existe une solution beaucoup plus simple à votre problème en utilisant awk plutôt que sed.

7
Ed Morton

Ce qui suit fonctionne sur Oracle Linux, x8664:

$ echo 'foobar' | sed 's/foo/foo\n/'
foo
bar

Si vous avez besoin de faire correspondre plus d'une fois par ligne, vous devrez placer un g à la fin, comme dans:

$ echo 'foobarfoobaz' | sed 's/foo/foo\n/g'
foo
barfoo
baz
0
ragerdl