Un de mes amis fait remarquer que si vous le faites:
perl -pi.bak -e 's/foo/bar/' somefile
quand "somefile" est en fait un lien symbolique, perl fait exactement ce que les docs disent qu'il fera:
Il le fait en renommant le fichier d'entrée, en ouvrant le fichier de sortie par le nom d'origine et en sélectionnant ce fichier de sortie par défaut pour les instructions print (). L'extension, si fournie, permet de modifier le nom de l'ancien fichier pour en faire une copie de sauvegarde [...]
Ce qui entraîne un nouveau lien symbolique "somefile.bak" pointant vers le fichier réel inchangé, et un nouveau fichier régulier modifié "somefile" avec les modifications.
Dans de nombreux cas, suivre le lien symbolique serait le comportement souhaité (même s'il laisse ambigu l'emplacement correct du fichier .bak). Existe-t-il un moyen simple de le faire autre que de tester les liens symboliques dans un wrapper et de gérer le cas de manière appropriée?
( sed
fait la même chose, pour ce que ça vaut.)
-p -i
dans votre script.Réponses:
Je me demande si le petit
sponge
utilitaire à usage général ("absorber l'entrée standard et écrire dans un fichier") de moreutils sera utile dans ce cas et s'il suivra le lien symbolique.L'auteur décrit
sponge
comme ceci:la source
sponge
un tel usage dans la pratique? Quant à moi: pas encore. Pourriez-vous s'il vous plaît laisser un commentaire indiquant s'il s'est comporté dans un test de la manière souhaitée ici? Oh, je vois le commentaire. Merçi pour la confirmation!file
dans votre exemple ci-dessus est un lien symbolique, le lien est laissé seul et le vrai fichier a été modifié.Si vous savez
somefile
pertinemment qu'il s'agit d'un lien symbolique, vous pouvez explicitement fournir le chemin d'accès complet au fichier avec les éléments suivants:perl -pi.bak -e 's/foo/bar/' $(readlink somefile)
De cette façon, le lien symbolique d'origine reste intact puisque le remplacement est désormais effectué directement avec le fichier d'origine.
la source
readlink
peut encore être un autre lien symbolique. Le mieux serait d'utiliser-f
ou-e
si disponible ouzsh
le qualificatif$file:P
ou(:P)
glob comme indiqué par @ikegami pour obtenir un chemin sans lien symbolique.Si vous avez affaire à un seul fichier, la commande se présente comme suit:
La solution est alors la suivante:
Cela gère à la fois les liens symboliques et les liens non symboliques.
Si vous traitez avec un nombre arbitrairement élevé de fichiers, la commande se présente comme suit:
La solution est alors la suivante:
Cela gère à la fois les liens symboliques et les liens non symboliques.
Caveat
readlink
n'est pas une commande standard, donc sa présence, ses arguments et ses fonctionnalités varient selon le système, alors assurez-vous de vérifier votre documentation. Par exemple, certaines implémentations ont-f
(que vous pouvez également utiliser ici), mais pas-e
, d'autres non plus.busybox
« sreadlink -f
se comporte comme GNUreadlink -e
. Et certains systèmes ont unerealpath
commande au lieu dereadlink
laquelle se comporte généralement comme GNUreadlink -f
.Attention avec GNU
readlink -e
, les liens symboliques qui ne peuvent pas être résolus vers un fichier existant sont supprimés en silence.la source
$var:P
ça ne marche pas pour moi. (X='tmp' zsh -c 'perl -E"say for @ARGV" $X:P'
sortiestmp:P
)$var:P
. Avec les anciennes versions, vous pouvez toujours utiliser à la$var:A
place. Voir le manuel pour les différences et zsh.org/mla/users/2016/msg00593.html pour la justification de l'introduction:P
(l'realpath()
interface réelle ).:A
été ajouté dans 4.3.10 (2009), GNUreadlink -z
en 2012, je ne connais aucune autrereadlink
implémentation qui prend en charge-z
). Notez qu'avec GNUxargs
, vous voulez généralement l'-r
option sauf si vous pouvez garantir que l'entrée ne sera pas vide. Ici, ce n'est pas grave (sauf si leperl
code contient une instructionBEGIN
/END
), vous obtiendrez simplement un-i used with no filenames on the command line, reading from STDIN.
avertissement si cela se produit.-r
la documentation. Je pensais avoir fait le contraire de ce qu'il fait. Readded.