6 votes

Plusieurs commandes sed en Bash

J'ai un fichier de noms d'utilisateurs et de mots de passe au format JSON que je veux convertir en traitement.

J'ai utilisé sed dans différentes commandes pour le traiter, mais ce que je voudrais savoir, c'est comment regrouper ces trois commandes en une seule pour l'avenir.

Format original

    { "user.name1" : "mot_de_passe_hashe",
"user.name2" : "mot_de_passe_hashe" }

Sortie souhaitée

user.name:mot_de_passe_hashe

Voici les commandes que j'ai exécutées, cependant je n'ai pas réussi à les enchaîner en utilisant soit la redirection ou simplement en les concaténant, ce qui me donne une erreur, sed: -e expression #1, char 8: option inconnue pour 's'.

Commande incriminée...

sed -i 's/\"//g/s/\,/\n/g/\s//g' fichier_entree 
sed: -e expression #1, char 8: option inconnue pour `s'

Comment pourraient les commandes ci-dessous être concaténées en une seule ?

Commandes Supprimer les guillemets doubles

sed -i 's/\"//g' fichier_entree

Remplacer la virgule par un saut de ligne

sed -i 's/\,/\n/g' fichier_entree

Supprimer les espaces

sed -i 's/\s//g fichier_entree

19voto

Attie Points 18031

Pour mettre plusieurs commandes sed dans un seul "script", vous pouvez utiliser plusieurs drapeaux -e (qui est portable) :

sed -i -e 's/\"//g' -e 's/\,/\n/g' -e 's/\s//g' fichier_d_entree

Ou le délimiteur point-virgule (qui n'est pas disponible sur toutes les implémentations) :

sed -i 's/\"//g;s/\,/\n/g;s/\s//g' fichier_d_entree

Vous aurez besoin de gérer les accolades également - {}...


Cela dit, pour analyser et manipuler correctement du JSON, vous ne devriez pas vraiment utiliser sed... essayez peut-être jq!

jq -r 'keys[] as $k | "\($k):\(.[$k])"' fichier_d_entree

Sortie :

user.name1:hashed_password
user.name2:hashed_password
  • keys[] as $k parcourra chaque clé en stockant sa valeur dans $k
    • c'est-à-dire: user.name1, user.name2
  • "\($k):\(.[$k])" formera une chaîne, en substituant $k et .[$k]
  • L'utilisation de -r enlève les guillemets des chaînes de sortie (mode raw)

Utiliser sed pour traiter du JSON va vous exposer à toute sorte de problèmes... par exemple, comment géreriez-vous l'entrée suivante (JSON complètement valide) ?

{
    "user.name1" :
        "hashed_password",
    "user.name2" :
        "hashed_password"
}

3voto

Bob Points 58080

Lorsque vous travaillez avec une entrée standardisée comme JSON, il est généralement préférable d'utiliser un vrai analyseur plutôt que regex. Par exemple, vous convertirez correctement toutes les séquences d'échappement (bien que cela puisse ne pas être possible avec vos données d'entrée spécifiques!).

Malheureusement, il n'y a pas d'excellents outils pour traiter le JSON dans coreutils. Attie a fourni jq comme une option décente si vous êtes libre d'installer des paquets.

Si vous ne pouvez pas installer de paquets supplémentaires, ce n'est pas particulièrement difficile en Python. Prenez par exemple ce script :

import json,sys
for (k, v) in json.load(sys.stdin):
    print(k + ":" + v)

Qui peut être compressé en une seule ligne :

cat inputdata | python -c 'import json,sys;print("\n".join((k + ":" + v) for (k, v) in json.load(sys.stdin).items()))'

0voto

J. Hansen Points 1

Pour la suppression de caractères simple que vous faites dans ces commandes sed, je recommanderais plutôt d'utiliser tr, dont le but principal est de supprimer, compresser ou remplacer des caractères individuels, y compris les sauts de ligne (sed est basé sur des regex, qui ont normalement besoin des sauts de ligne comme séparateurs de tampon, donc utiliser sed pour modifier les sauts de ligne est délicat). Je pense que cette commande tr fait tout ce que vous cherchez à faire :

cat nom_fichier_json | tr -d "{}\" \012\011\015" | tr "," "\012"

La première commande tr supprime toutes les accolades, les guillemets, les espaces, les retours chariot (octal 012, ascii 10), les tabulations (octal 011, ascii 9), et les sauts de ligne (octal 015, ascii 13). La deuxième commande tr remplace toutes les virgules par des sauts de ligne. Tant que les noms de variables et les valeurs de votre fichier JSON ne contiennent pas de virgules, ces commandes vous permettraient d'éviter d'avoir besoin d'un parseur JSON dédié.

Cela dit, si vous avez un ensemble de commandes sed qui fonctionnent indépendamment, les combiner pourrait être le plus facile à réaliser en utilisant l'option "-f" de sed pour lire les commandes séparées depuis un fichier. Vous mettez simplement les chaînes s/.../.../g dans un fichier, chaque chaîne sur sa propre ligne, puis spécifiez ce nom de fichier après l'option "-f". Par exemple, si les trois commandes sed que vous avez listées sont satisfaisantes, vous pourriez les mettre dans un fichier nommé "json.convert.sed" qui contient simplement ceci :

s/\"//g 
s/\,/\n/g
s/\s//g

Ensuite, vous invoqueriez sed avec ce fichier de commandes en utilisant :

sed -f json.convert.sed

Cela dit, ces commandes sed ne fonctionnent pas pour moi pour accomplir ce que vous voulez, et je ne suis pas certain que vous puissiez jamais obtenir sed pour modifier les sauts de ligne. C'est parce que sed est basé sur l'ancien éditeur de lignes "ed", conçu pour éditer des lignes individuellement (une version scriptable), donc chaque ligne d'entrée est "analysée" en utilisant les sauts de ligne comme délimiteurs, puis la ligne (sans le saut de ligne) est passée au moteur d'édition, les commandes d'édition sont appliquées, puis la ligne éditée est renvoyée avec un saut de ligne. Ensuite, la boucle se répète. J'ai seulement pu utiliser sed pour modifier un saut de ligne en changeant d'abord les sauts de ligne en un caractère distinct (qui n'apparaît pas autrement dans l'entrée) en utilisant tr. Il n'y a pas d'intérêt à utiliser tr de cette façon si tout ce que vous voulez faire est de supprimer des sauts de ligne, car tr le fera pour vous. Mais si, par exemple, vous vouliez convertir des sauts de ligne en points-virgules avec un espace à la fin, une façon de le faire serait :

cat fichier_entree | tr "\012" "%" | sed "s/%/; /g"

(les sauts de ligne sont convertis en % par tr, puis sed convertit tous les caractères % en paires de caractères ";".)

0voto

MatlabSorter Points 726

Sed peut gérer l'édition sur plusieurs lignes, mais je suis d'accord avec Attie et Bob, l'analyse json avec des regex sed peut devenir un cauchemar.

sed -nr '/\{/ b Load ; d
: Load
/\}/ b Edit ; N ; b Load
: Edit ; s/[^"]+"([^"]+)"[^"]+"([^"]+)"(.*)/\1:\2\n\3/ ; t Print ; d
: Print ; P ; s/[^\n]+\n// ; t Edit' <<'eof'
{
    "user.name1" :
        "hashed_password1",
    "user.name2" :
        "hashed_password2"
}
    { "user.name3" : "hashed_password3",
"user.name4" : "hashed_password4" }

{ "user.name5":"hashed_password5"}
eof

user.name1:hashed_password1
user.name2:hashed_password2
user.name3:hashed_password3
user.name4:hashed_password4
user.name5:hashed_password5

-1voto

Eloy Points 158

Vous pourriez le combiner comme ceci:

sed -i 's/\"//g;s/\,/\n/g;s/\s//g' input_file

vous avez oublié d'ajouter la suppression de {}. Donc vous voulez probablement:

sed -i 's/\"//g;s/\,/\n/g;s/\s//g;s/{//g;s/}//g' input_file

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X