Sed avec l'édition in situ change la propriété du groupe du fichier

8

J'ai un phpscript shell ( ) qui entre en contact avec le fichier cible de cette façon:

  • si Inspecte fichier et répertoire sont inscriptibles avec phpl » is_writable()(je ne pense pas que ce problème)
  • modifie le fichier sur place avec la sedcommande:

grep -q "$search" "$passwd_file" && { sed -i "s|$search|$replace|" "$passwd_file"; printf "Password changed!\n"; } || printf "Password not changed!\n"

En conséquence, je reçois (tout le reste est correct, mais) le fichier qui devait myuser:www-dataêtre myuser:myuser.

La sedpropriété du groupe de fichiers change- t- elle comme il semble, et comment l'éviter, si possible?

Miloš Đakonović
la source

Réponses:

16

Il y a un petit problème avec sedle mode d'édition sur place -i. sedcrée un fichier temporaire dans le même répertoire appelé sedy08qMA, où y08qMAest une chaîne générée aléatoirement. Ce fichier est rempli avec le contenu modifié du fichier d'origine. Après l'opération, sedsupprime le fichier d'origine et renomme le fichier temporaire avec le nom de fichier d'origine. Ce n'est donc pas une véritable modification in situ . Il crée un nouveau fichier avec les autorisations de l'utilisateur appelant et un nouveau numéro d'inode. Ce comportement n'est généralement pas mauvais, mais par exemple, les liens durs sont rompus.

Cependant, si vous souhaitez une véritable édition sur place, vous devez utiliser ed. Il lit les commandes de la stdin et édite le fichier directement, sans fichier temporaire (c'est fait sur edle tampon mémoire de). Une pratique courante consiste à utiliser printfpour générer la liste de commandes:

printf "%s\n" '1,$s/search/replace/g' wq | ed -s file

La printfcommande produit la sortie comme suit:

1,$s/search/replace/g
wq

Ces deux lignes sont des edcommandes. Le premier recherche la chaîne searchet la remplace par replace. Le second écrit ( w) les modifications apportées au fichier et quitte ( q). -ssupprime la sortie de diagnostic.

le chaos
la source
8

Le -iparamètre sedfonctionne en créant un fichier temporaire pendant le fonctionnement, puis en remplaçant le fichier réel par le fichier temporaire à la fin. C'est probablement la cause du problème, car lors de la création du propriétaire du fichier temporaire, la valeur par défaut estmyuser:myuser

Vous pouvez définir le setgidbit sur le répertoire parent (uniquement si le répertoire parent appartient au groupe www-data), de sorte que les fichiers créés sous ce répertoire héritent du même groupe.
pour faire ça:

chmod g+s parent-dir-of-your-file  

Je pense que c'est une utilisation très typique du setgidbit.

Dave.d
la source
@cuonglm Je viens de faire un strace sed -i, j'ai trouvé la ligne suivante dans la trace, cela signifie-t-il qu'il a créé le fichier temporaire dans le répertoire actuel? open("./sedKyG9Ei", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
Dave.d
@DavidDai: Oui, ma mauvaise mémoire.
cuonglm
2

L'utilisation de edau lieu de sedsemble plutôt superflue pour cela, étant donné que vous devez ajouter une entrée supplémentaire. La distribution sur laquelle je travaille en ce moment (CentOS 5.10) a l' -coption sedqui utilise la «copie» du fichier temporaire plutôt que de simplement le renommer lorsqu'elle est utilisée avec l' -ioption. Je l'ai testé et cela a fonctionné parfaitement, préservant le propriétaire et le groupe d'origine lors d'une modification en ligne. Il ne conserve PAS l'heure de modification.

par exemple, sed -ci -e '3,5d' file.txt

  • -c utilise la copie au lieu de renommer (c.-à-d. préserve la propriété / le groupe)
  • -i édition en ligne
  • -e script / expression à exécuter

Je ne sais pas à quel point cette option est répandue seddans d'autres distributions. Solaris 10 ne l'avait pas, mais Solaris n'a pas beaucoup de choses que je veux.

devnulldad
la source
Cela semble assez pratique. Pas dans Ubuntu 14.04 cependant, FWIW. :-(
John Rix