Modifier une ligne d'un fichier

Premièrement, je demande confirmation de ma compréhension de cette ligne :

"ligne 26 du fichier /etc/truc, remplacer ‘yes’ par ‘no’"
Exact :question:
Je voudrais faire un script sensiblement identique où il faudrait remplacer le dernier mot par un autre.
Problème, le N° de ligne risque de ne pas être fixe et il me faut donc trouver un moyen de reconnaitre cette ligne, par exemple, par son premier mot qui lui, est unique.
Il me semble avoir déjà demandé ça ici mais je ne retrouve pas le fil.
La requête serait donc :
Dans le fichier /etc/machin, sur la ligne qui commence par ‘blabla’, remplace le dernier mot par 'trucmuche’
Est-ce possible ?
Merci.

Bien sûr avce awk par exemple :

Il ne fait par contre pas de inplace donc :

Merci Michel mais ce n’est pas très clair pour moi, peux-tu me détailler un peu la progression.

Désolé, je suis allé un peu vite.
awk a une syntaxe assez simple les “commandes” sont de la forme :

CONDITION { CODE } CONDITION { CODE } CONDITION { CODE }

Pour chaque entrée des fichiers passés en paramètre (ou chaque entrée de son entrée standard), il vérifie tour à tour chaque condition.
Si une condition est vrai, il exécute le code qui se trouve entre accolade. Par défaut une entrée est une ligne (séparé par un \n), mais ça peu être n’importe quel séparateur.

Ici on a 2 blocs :

et

La condition du premier “/mot/” est une version courte de “$0 ~ /mot/”. C’est la recherche d’une expression régulière dans la ligne ($0 c’es une variable qui représente la ligne courante). Donc ici la condition va être vérifiée pour chaque ligne qui contient “mot”. Pour ces lignes il va exécuter le code correspondant : {NF=“no”;print}. Il faut savoir qu’awk découpe les entrées par défaut sur les caractères d’espacement (ce qui revient à découper en mot). Chacun va dans une variable $1, $2, $3, $4, etc jusqu’à NF (number field). On veut modifier le dernier mot de la ligne donc NF="no"
print prend par défaut la variable $0 et prend en compte les modifications courantes de la ligne.

Le second bloc c’est la condition inverse et par défaut quand on met pas de code c’est “{print $0}” qui est exécuté.

On aurait pu être plus précis et écrire :

Pour les lignes dont le premier mot est “export”, on remplace le dernier mot par “coucou”.
On affiche chaque ligne (sans condition).

Note mon exemple du message précédent est faut il faut remplacer NF par $NF.

Si tu n’as pas compris n’hésite pas à redemander :slightly_smiling:

Ça c’est de l’explication complète comme je les aime :023
Moi, pôv débutant, si on ne me met pas les points sur les ‘i’, se ne pige pas. Et comme je n’aime pas faire bêtement les choses si je ne les comprends pas, il faut que ça “rentre” et c’est parfois long :unamused:
Maintenant, j’ai parfaitement compris le processus.
Par contre, j’avais certainement mal interprété ta phrase précédente

Il ne fait par contre pas de inplace donc :

Ce terme ‘inplace’, je l’avais compris comme “remplace” et j’avais donc pensé que Awk ne savait pas remplacer seulement un mot par un autre et qu’il fallait donc lui faire remplacer TOUT le fichier.
Tu me prouves le contraire là :

Pour les lignes dont le premier mot est "export", on remplace le dernier mot par "coucou".

Je teste ça cet AM.
merci encore.
:006

[quote=“ricardo”]Ça c’est de l’explication complète comme je les aime :023
Moi, pôv débutant, si on ne me met pas les points sur les ‘i’, se ne pige pas. Et comme je n’aime pas faire bêtement les choses si je ne les comprends pas, il faut que ça “rentre” et c’est parfois long :unamused: [/quote]
C’est tout à ton honneur, ne t’inquiète pas. awk (comme un paquet de trucs liés au shell) est assez compliqué à expliquer, mais se forcer à le faire est une très bonne chose (et ça fait partie du partage).

Edit. : J’ai commencé une page sur le wiki à ce sujet isalo.org/wiki.debian-fr/Awk

Le « sur place », c’est surtout pour faire comme le -i de sed. Avec sed tu lui dis :

sed -i 's/yes/no/g' fichier

et « fichier » est modifié. Avec awk il faut faire :

awk '...' fichier > new_fichier mv new_fichier fichier

Awk travail sur une copie du fichier en mémoire (copie partielle si tu travail sur un fichier de plusieurs Gio il ne va pas charger tout le fichier d’un coup), avec print on écris au fur et à mesure le fichier sur la sortie standard qu’on redirige ensuite où l’on souhaite. C’est moins pratique.

À noter que sed ne fait pas d’optimisations, si on lance sed ainsi :

find -exec sed -i 's/kjdsk/sjkdhkf/' '{}' \;

Tout les fichiers seront modifiés, même si leur contenu ne l’est pas (qu’il n’y a eu aucun remplacement effectif).
Ça se remarque bien avec make, dans ces cas il est bon d’utiliser grep avant par exemple :

grep -rl 'kjdsk' . | xargs sed -i 's/kjdsk/sjkdhkf/'

(on commence par lister les fichiers qui vont devoir être modifié et on les modifie)

Ta dernière explication est valable surtout quand il peut y avoir plusieurs occurrences, plusieurs lignes qui commencent par le même mot et donc plusieurs lignes à traiter.
Dans mon cas précis, où je sais ne devoir modifier qu’une seule ligne (la seule qui commence par “blabla”) et où je veux remplacer “no” par “yes”, sed semble être plus court (une seule ligne) non ?

Ça, j’ai testé et ça fonctionne.
Si je fais avec awk, il faut deux lignes de commande puisqu’il faut ensuite renommer le fichier modifié, non ?

Je vais aller faire un tour sur le wiki.

[quote=“ricardo”]Ta dernière explication est valable surtout quand il peut y avoir plusieurs occurrences, plusieurs lignes qui commencent par le même mot et donc plusieurs lignes à traiter.
Dans mon cas précis, où je sais ne devoir modifier qu’une seule ligne (la seule qui commence par “blabla”) et où je veux remplacer “no” par “yes”, sed semble être plus court (une seule ligne) non ?

En effet. Fait tout de même gaffe, il faudrait peut être mieux écrire :

Pour être sûr de modifier le dernier mot.

[quote=“MisterFreez”][quote=“ricardo”]Ta dernière explication est valable surtout quand il peut y avoir plusieurs occurrences, plusieurs lignes qui commencent par le même mot et donc plusieurs lignes à traiter.
Dans mon cas précis, où je sais ne devoir modifier qu’une seule ligne (la seule qui commence par “blabla”) et où je veux remplacer “no” par “yes”, sed semble être plus court (une seule ligne) non ?

En effet. Fait tout de même gaffe, il faudrait peut être mieux écrire :

Pour être sûr de modifier le dernier mot.[/quote]
2 questions de plus :
1/
Je comprends bien la précision de l’espacement mais pourquoi doit-on ajouter ‘$’ à ‘no’ :question:
[:space:]no$

2/
sed sait-il trouver la dernière chaine quelle qu’elle soit :question:
J’explique :
au lieu de préciser qu’il doit remplacer ‘no’ par 'yes, l’idéal serait de lui dire de remplacer le ‘dernier mot’ de la ligne par ‘yes’.

EDIT :
en ne mettant que le ‘$’ ???

[quote=“ricardo”]
2 questions de plus :
1/
Je comprends bien la précision de l’espacement mais pourquoi doit-on ajouter ‘$’ à ‘no’ :question:
[:space:]no$[/quote]
$ représente la fin de ligne. Donc dans l’exemple il cherche un caractère d’espacement suivi de no et plus rien derrière (si ce n’est un \n).

[quote=“ricardo”]2/
sed sait-il trouver la dernière chaine quelle qu’elle soit :question:
J’explique :
au lieu de préciser qu’il doit remplacer ‘no’ par 'yes, l’idéal serait de lui dire de remplacer le ‘dernier mot’ de la ligne par ‘yes’.

EDIT :
en ne mettant que le ‘$’ ???[/quote]
C’est possible, mais pas comme ça. Ainsi par exemple :

Petite explication :
[ul]
[li](.[[:space:]]) : on récupère dans un groupe () n’importe quel suite de caractère . suivi d’un caractère d’espacement [:space:][/li]
[li][^[:space:]]+ : on vérifie l’existence d’un caractère ou plus + qui n’est pas [^…] un caractère d’espacement à la fin $[/li]
[li]on remplace le tout par le groupe \1 suivi de yes[/li][/ul]

Comme on fait une recherche complète tu peut faire ça :

Impec, j’ai toutes mes réponses.
Tu es un super prof :023

[quote=“MisterFreez”]…

Comme on fait une recherche complète tu peut faire ça :

Testé : ça fonctionne mais ça double la ligne modifiée quand je mets le chemin à la place de ‘coucou’.
J’ai donc supposé que le ‘p’ était là pour un test de réponse et je l’ai supprimé.
Résultat : impec !
Ma requête était pour créer un mini script qui modifie la possibilité d’authentification par MDP dans sshd_config.
Je travaille avec des clefs accompagnées de passphrases et je supprime donc la possibilité de connexion par MDP en temps normal. Parano, moi, non … fou :083
Toutefois, je veux pouvoir “ouvrir” ponctuellement cette possibilité, effectuer ce que je dois faire de façon rapide, et “refermer” aussitôt.
Ce script (et son jumeau pour la fonction inverse) me permettra de faire ça avec un minimum de réflexion.
Pourquoi la recherche de n’importe quelle chaine, à la place de ‘yes’ ?
Tout simplement pour ne pas avoir à vérifier l’état avant. Ainsi, même si je suis déjà à ‘yes’, il ne râlera pas si je lui demande de le refaire.

[quote=“MisterFreez”]
C’est possible, mais pas comme ça. Ainsi par exemple :

Petite explication :
[ul]
[li](.[[:space:]]) : on récupère dans un groupe () n’importe quel suite de caractère . suivi d’un caractère d’espacement [:space:][/li]
[li][^[:space:]]+ : on vérifie l’existence d’un caractère ou plus + qui n’est pas [^…] un caractère d’espacement à la fin $[/li]
[li]on remplace le tout par le groupe \1 suivi de yes[/li][/ul]

Comme on fait une recherche complète tu peut faire ça :

Dans la dernière ligne, je ne comprends pas bien l’utilité de ‘.*’ puisque je connais exactement la chaine de début de ligne : ‘blabla’ :question:

[quote=“ricardo”]Testé : ça fonctionne mais ça double la ligne modifiée quand je mets le chemin à la place de ‘coucou’.
J’ai donc supposé que le ‘p’ était là pour un test de réponse et je l’ai supprimé.[/quote]
C’est en effet le cas. J’utilise l’option -n de sed et p de s/// pour les tests.

[quote=“ricardo”]Toutefois, je veux pouvoir “ouvrir” ponctuellement cette possibilité, effectuer ce que je dois faire de façon rapide, et “refermer” aussitôt.
Ce script (et son jumeau pour la fonction inverse) me permettra de faire ça avec un minimum de réflexion.
Pourquoi la recherche de n’importe quelle chaine, à la place de ‘yes’ ?
Tout simplement pour ne pas avoir à vérifier l’état avant. Ainsi, même si je suis déjà à ‘yes’, il ne râlera pas si je lui demande de le refaire.[/quote]
Quelque soit ton script au vu de sa description, je pense qu’il peut être amélioré :slightly_smiling:
Je trouve dommage de relancer le serveur ssh alors que tu n’a pas modifié sa configuration (plus précisément tu l’a modifié à l’identique).
Tu parle d’un script et de son jumeau c’est dommage d’un point de vu maintenabilité, tu pourrais en avoir un qui prend des options ou alors en avoir un et un lien vers lui et en fonction de comment se nome le script il réagis différemment.

Parce que je suis un pro et que tu ne me l’avais pas dis (tu m’as dis que tu savais comment commence la ligne). Je me doutais de genre de fichier dont il s’agit mais j’ai l’habitude d’essayer de correspondre exactement aux contraintes qu’on me donne (c’est un exercice). Pour ton cas d’usage tu peut faire ça :

Allez, c’est parti, on va “améliorer” … si tu es disponible :laughing:
On va procéder une chose à la fois pour éviter le croisement de réponses :

Que représente le ‘*’ :question:

0, un ou plusieurs fois le caractère (ou la classe de caractères) précédente. Ici c’est [:space:] la classe de caractère précédente : les caractère d’espacement (espace et tabulation entre autre).

La question c’est : qu’est ce que tu préfère ?
Ça :

$ permit_passwd
Le login par mot de passe est autorisé
$ permit_passwd off
$ permit_passwd status
Le login par mot de passe n'est pas autorisé
$ permit_passwd on

J’ai rien affiché à l’exécution de on et off, mais bien sûr on peut l’ajouter.
Ou bien :

$ status_permit_passwd
Le login par mot de passe est autorisé
$ status_permit_passwd
$ forbid_passwd
Le login par mot de passe n'est pas autorisé
$ permit_passwd

Personnellement je préfère le premier (mais c’est tout personnel).

Tu me parles de choix possibles ?
Je ne sais comment traduire mais ce que je veux, c’est être dans la généralité du temps avec “impossibilité de se connecter” avec pass
MAIS
pouvoir le faire exceptionnellement de façon pratique donc simple et c’est pour ça que j’ai pensé à ce script dans /etc/ssh/sshd_config.
Retour cet AM
:006

EDIT :
Mes raisons de vouloir pratiquer ainsi :
1/ Pas besoin de connexion via MDP, c’est 99 % du temps :
– Que ce soit en “local” ou en “extérieur”, je me connecte sur mon serveur en SSH/sftp/etc avec des clefs et passphrase.
– Pour placer des photos sur Piwigo, si je le fait de façon classique, pas de problème mais c’est assez long car il faut créer a la mano des ‘miniatures’.

2/ Besoin de connexion via MDP, 1% du temps :
– Pour éviter cette pratique fastidieuse de Piwigo classique, il y a “pLoader” qui fait tout en un clin d’œil, MAIS, il n’accepte pas la connexion par clefs avec passphrase.
Idem avec FileZilla si je veux déplacer des dossiers de façon rapide (mais je fais aussi en ligne)
– De plus, un correspondant ne réussit pas à se connecter en sftp avec les clefs, malgré de nombreux essais, bien que tous les autres y arrivent.
– Il y a aussi qq membres de la famille à qui il est inutile de leur parler d’installer un jeu de clefs :unamused:
Donc, pour ces cas, j’ai besoin de pouvoir accepter ‘temporairement’ la connexion via MDP.

Plop,

[quote=“ricardo”][…]
– Pour placer des photos sur Piwigo, si je le fait de façon classique, pas de problème mais c’est assez long car il faut créer a la mano des ‘miniatures’.[/quote]

Ça se scripte aussi ça, avec imagemagick, qui garde les méta-données EXIF/IPTC/XMP.

J’ai un script python qui me fait ça en fonction de l’orientation de l’image, mais ça doit se faire directement en bash aussi (j’y connais rien en bash).

Si mon script intéresse, je peux le travailler un peu et le mettre en trucs & astuces.

Usti

[quote=“Ustilago”]Plop,

[quote=“ricardo”][…]
– Pour placer des photos sur Piwigo, si je le fait de façon classique, pas de problème mais c’est assez long car il faut créer a la mano des ‘miniatures’.[/quote]

Ça se scripte aussi ça, avec imagemagick, qui garde les méta-données EXIF/IPTC/XMP.

J’ai un script python qui me fait ça en fonction de l’orientation de l’image, mais ça doit se faire directement en bash aussi (j’y connais rien en bash).

Si mon script intéresse, je peux le travailler un peu et le mettre en trucs & astuces.

Usti[/quote]
Bien sûr que c’est intéressant, il y a pas mal de membres qui utilisent Piwigo comme galerie-photos.
Poste ton script dans T&A et donne un maximum d’explications.