Créer un fichier CSV à partir d'un fichier texte avec des jetons d'en-tête à l'aide de scripts shell

Je souhaite créer un fichier CSV à partir d'un ensemble de fichiers texte dans un répertoire avec la structure suivante pour les importer ultérieurement dans une base de données.

Title:
Article title
Word Count:
100
Summary:
Article summary.
Can consist of multiple lines.

Keywords:
keyword1, keyword2, keyword3
Article Body:
The rest of the article body.
Till the end of the file.

Le résultat souhaité est donc de les avoir dans un fichier CSV avec des sections comme en-têtes avec leur contenu comme suit.

Title | Word Count | Summary  | Keywords  | Article Body |
Article title | 100 | Article summary.\nCan... | keyword1, keyword2, keyword3 |... |
Article2 title | 110 | Article summary.\nCan... | keyword1, keyword2, keyword3 |... |

J'ai essayé quelques approches avec des scripts awk et shell, mais je n'ai pas réussi jusqu'à présent. Des idées?


Solution du problème

Selon la documentation de COPY, PostgreSQL prend entièrement en charge le format CSV, ainsi qu'un format TEXT qui est par défaut compatible avec le format TSV sans perte.

Parce que j'utilise awk, je choisis de sortir un format TSV. La raison en est qu'il y a des nouvelles lignes dans les données et POSIX awkne permet pas de stocker des nouvelles lignes littérales dans une variable définie par l'utilisateur. Le format TSV n'a pas ce problème car vous remplacerez les retours à la ligne par \ndans les données.

De plus, j'ai modifié le format d'entrée pour faciliter l'analyse. La règle est qu'une ou plusieurs lignes vides délimitent les blocs, ce qui signifie que vous ne pouvez plus avoir de lignes vides dans le contenu de Summaryou Article Bodyplus (j'ai ajouté un espace dans l'exemple).

Exemple d'entrée :

Title:
Article title
Word Count:
100
Summary:
Article summary.

Can consist of multiple lines.
Keywords:
keyword1, keyword2, keyword3
Article Body:
The rest of the article body.

Till the end of the file.

Et voici la awkcommande (qui est capable de traiter plusieurs fichiers en une seule fois) :

edit : les noms des champs dans l'en-tête sont maintenant convertis en cas de serpent

awk -v RS='' -v FS='^$' -v OFS='\t' '
FNR == 1 { fn++ }
/^[^:\n]+:/ {
fieldName = substr($0,1,index($0,":")-1)
sub("^[^:]+:[^\n]*\n","")
gsub(/\\/,"\\\\")
gsub(/\n/,"\\n")
gsub(/\r/,"\\r")
gsub(/\t/,"\\t")
header[fieldName]
record[fn,fieldName] = $0
}
END {
out = sep = ""
for (fieldName in header) {
gsub(/ /,"_",fieldName)
out = out sep tolower(fieldName)
sep = OFS
}
print out
for (i = 1; i <= fn; i++) {
out = sep = ""
for (fieldName in header) {
out = out sep record[fn,fieldName]
sep = OFS
}
print out
}
}
' *.txt

Le résultat:

summary article_body word_count title keywords
Article summary.\n \nCan consist of multiple lines. The rest of the article body.\n \nTill the end of the file. 100 Article title keyword1, keyword2, keyword3

PS: Une fois que vous avez un fichier TSV valide, vous pouvez utiliser un autre outil comme mlrpour le convertir en CSV, JSON, etc... mais dans le but de l'importer dans postgreSQL, ce n'est pas obligatoire.

Voici la commande SQL (non testée) :

COPY tablename FROM '/path/file.tsv' HEADER;

note : Il semble que vous n'ayez pas besoin de spécifier le FORMATni le DELIMITERcar les valeurs par défaut sont textet\t

Commentaires

Posts les plus consultés de ce blog

Erreur Symfony : "Une exception a été levée lors du rendu d'un modèle"

Détecter les appuis sur les touches fléchées en JavaScript

Une chaîne vide donne "Des erreurs ont été détectées dans les arguments de la ligne de commande, veuillez vous assurer que tous les arguments sont correctement définis"