(Cette question fait suite à ce commentaire, dans une réponse à propos des hooks git)
Je suis bien trop peu qualifié en bash (jusqu'à présent) pour comprendre pleinement la remarque et comment agir en conséquence. Plus précisément, on m'a conseillé d'éviter d'utiliser la commande bash cat
de cette façon:
tmp = "$1" echo "$current_branch" $(cat $tmp) > "$1"
car l'ordre des opérations dépend du shell spécifique et cela pourrait finir par détruire le contenu de l'argument passé, donc le message de validation lui-même si je l'ai bien compris?
Aussi, comment "enregistrer le contenu dans une étape séparée"?
Est-ce que ce qui suit aurait du sens?
echo "$current_branch" $(cat "$1") > "$1"
3 Réponses :
À mon avis, il vaut mieux enregistrer dans un autre fichier.
Vous pouvez essayer quelque chose comme
echo "$current_branch" > tmp cat "$1" >> tmp # merge these into # echo "$current_branch" $(cat "$1") > tmp # may both OK mv tmp "$1"
Cependant, je ne suis pas sûr si je comprends bien, ou il existe de meilleures solutions.
C'est ce que je considérais comme le cœur de la question. Il est difficile de décider de la "priorité" du bloc $ ()
et de >
. Si >
est exécuté "plus tôt", alors echo "$ current_branch"
réécrira le fichier "$ 1" et supprimera le contenu original de "$ 1" , ce qui est un désastre. Si $ ()
est exécuté "plus tôt", alors tout fonctionne comme prévu. Cependant, il existe un risque et nous devons l’éviter.
Je vais mieux maintenant, merci pour les explications. Je vais l'essayer et jouer avec.
Le problème proposé ne concerne pas l'écrasement de variables ou d'arguments, mais le fait que lire et écrire dans un fichier en même temps est généralement une mauvaise idée.
Par exemple, cette commande peut sembler écrivez simplement un fichier sur lui-même, mais à la place, il le tronque:
tmp=$(mktemp) || exit echo "$current_branch $(cat "$1")" > "$tmp" mv "$tmp" "$1"
Cependant, ce n'est pas un problème dans votre commande spécifique. Il est garanti de fonctionner dans un shell compatible POSIX car l'ordre des opérations spécifie que les redirections se produiront après les expansions:
Les mots qui ne sont pas des affectations de variables ou des redirections doivent être développés. Si des champs restent après leur développement, le premier champ sera considéré comme le nom de la commande et les champs restants seront les arguments de la commande.
Les redirections doivent être effectuées comme décrit dans Redirection.
Double-cependant , c'est encore un peu fragile dans le sens où des modifications apparemment inoffensives peuvent déclencher le problème, par exemple si vous vouliez exécuter sed
sur le résultat. Puisque la redirection (> "$ 1"
) et la substitution de commande $ (cat "$ 1")
sont désormais dans des commandes séparées, la définition POSIX ne vous sauve plus: p >
# Command will now always delete the original message modify_message() { echo "$current_branch $(cat "$1")" } modify_message "$1" > "$1"
De même, si vous le refactorisez en une fonction, il cessera également de fonctionner soudainement:
# Command may now randomly result in the original message being deleted echo "$current_branch $(cat "$1")" | sed -e 's/(c)/©/g' > "$1"
Vous pouvez éviter cela en écrivant dans un fichier temporaire, puis remplacez votre original.
cat myfile > myfile # Truncates the file to size 0
Réponse exceptionnelle, merci beaucoup! Question de suivi: le fichier temporaire ne serait-il pas suspendu par la suite? Je veux dire, il ne devrait pas être détecté par git comme un fichier non suivi ou entraver le processus sinon, je devrais donc m'en débarrasser dans le processus, non?
@RomainValeri Dans cet exemple, mv
est utilisé pour déplacer le fichier temporaire de votre hook et remplacer le fichier temporaire de git, il ne reste donc plus de fichier. Si vous aviez fait par exemple cat "$ tmp"> "$ 1"
alors vous auriez raison: il aurait fallu un rm "$ tmp"
séparé pour nettoyer le fichier temporaire.
Vous n'êtes pas le type autre , vous êtes le gars ;-)
Un groupe de commandes serait bien mieux qu'une substitution de commandes ici. Notez la similitude avec la réponse de Geno Chen.
{ echo "$current_branch" cat "$1" } > tmp && mv tmp "$1"
Puis-je simplement demander à quel point ce serait mieux? J'ai peur de ne pas savoir ce que vous appelez la substitution de commande ici: - /
$ (...)
est une substitution de commande, et cela nécessite que tout le contenu du fichier soit d'abord lu en mémoire. (Il supprime également toutes les nouvelles lignes de fin, ce qui nécessite un peu de manipulation pour contourner.) Cela écrit simplement la sortie de la commande echo
, suivie de la sortie du code cat > commande, dans le fichier temporaire. (Sémantiquement, c'est la même chose que d'écrire puis d'ajouter à un fichier, mais il suffit d'ouvrir
tmp
une fois et est syntaxiquement plus propre.)