J'écris des scripts shell pour mon serveur, qui est un hébergement partagé sous FreeBSD. Je veux aussi pouvoir les tester localement, sur mon PC sous Linux. Par conséquent, j'essaie de les écrire de manière portable, mais sed
je ne vois aucun moyen de le faire.
Une partie de mon site Web utilise des fichiers HTML statiques générés, et cette ligne sed insère le DOCTYPE correct après chaque régénération:
sed -i '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
Cela fonctionne avec GNU sed
sous Linux, mais FreeBSD sed
s'attend à ce que le premier argument après l' -i
option soit l'extension de la copie de sauvegarde. Voici à quoi cela ressemblerait:
sed -i '' '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
Cependant, GNU sed
s'attend à ce que l'expression suive immédiatement après -i
. (Cela nécessite également des correctifs avec la gestion des nouvelles lignes, mais cela a déjà été résolu ici )
Bien sûr, je peux inclure ce changement dans la copie du script que je suis sur le serveur, mais cela gâcherait mon utilisation de VCS pour la gestion des versions. Existe-t-il un moyen d'y parvenir avec sed de manière totalement portable?
-i
Réponses:
GNU sed accepte une extension optionnelle après
-i
. L'extension doit être dans le même argument sans espace intermédiaire. Cette syntaxe fonctionne également sur BSD sed.Notez que sous BSD,
-i
modifie également le comportement lorsqu'il y a plusieurs fichiers d'entrée: ils sont traités indépendamment ($
correspond par exemple à la dernière ligne de chaque fichier). De plus, cela ne fonctionnera pas sur BusyBox.Si vous ne souhaitez pas utiliser de fichiers de sauvegarde, vous pouvez vérifier quelle version de sed est disponible.
Ou bien, pour éviter de brouiller les paramètres de position, définissez une fonction.
Si vous ne voulez pas vous déranger, utilisez Perl.
Si vous voulez écrire un script portable, n'utilisez pas
-i
- ce n'est pas dans POSIX. Faites manuellement ce que sed fait sous le capot - ce n’est plus qu’une ligne de code.la source
sed -i
implique également-s
. Et le moyen le plus simple de rechercher une unité GNU consiste à utilisersed
lased v
commande qui est un noop valide pour GNU mais qui échoue partout ailleurs.sed -i$(sed v < /dev/null 2> /dev/null || echo -n " ''") -e '...' "$file"
Si ce n'est pas GNU sed, il insère un espace suivi de deux citations de singe après-i
afin qu'il fonctionne sur BSD. GNU sed obtient seulement-i
.v
commande pour tester GNU sed. Et si FreeBSD décidait de l'implémenter?sed v
étant donné que c'est son objectif d'exister.Si vous ne trouvez pas d'astuce pour rendre le
sed
jeu agréable, vous pouvez essayer:Ne pas utiliser
-i
:Utilisez Perl
la source
ed
Vous pouvez toujours utiliser
ed
pour ajouter une ligne à un fichier existant.Détails
Les bits autour de
<!DOCTYPE html>
sont des commandes pour luied
demander d’ajouter cette ligne au fichiermy.html
.sed
Je crois que cette commande
sed
peut aussi être utilisée:la source
Vous pouvez également faire manuellement ce que
perl -i
fait sous le capot:Par exemple
perl -i
, il n'y a pas de sauvegarde, et comme la plupart des solutions données ici, prenez garde que cela peut affecter les autorisations, la propriété du fichier et peut transformer un lien symbolique en un fichier normal.Avec:
sed
écraserait le fichier sur lui-même, n'affecterait donc pas la propriété, les permissions ou les liens symboliques. Cela fonctionne avec GNUsed
carsed
il a généralement lu un tampon plein de donnéesfile
(4k dans mon cas) avant de l’écraser avec lai
commande. Cela ne fonctionnerait pas si le fichier comptait plus de 4k, à part le fait quesed
sa sortie tamponne également.Fonctionne essentiellement
sed
sur des blocs de 4k pour la lecture et l’écriture. Si la ligne à insérer est inférieure à 4k,sed
ne remplacera jamais un bloc qu'il n'a pas encore lu.Je ne compterais pas dessus cependant.
la source
echo '<!DOCTYPE html>'
ou échappé sans "" guillemets.FreeBSD sed , qui est également utilisé sur Mac OS X, a besoin de l’
-e
option après le-i
commutateur pour définir et reconnaître la commande suivante (regex) correctement et sans ambiguïté.En d'autres termes,
sed -i -e ...
devrait fonctionner à la fois avec FreeBSD et GNUsed
.Plus généralement, l'omission de l'extension de sauvegarde après FreeBSD
sed -i
nécessite unesed
option ou un commutateur explicite-i
pour éviter toute confusion avec FreeBSDsed
lors de l'analyse de ses arguments de ligne de commande.(Notez cependant que
sed
les modifications de fichiers sur place entraînent des modifications d'inode de fichier, voir Modification de fichiers "sur place" ).(En règle générale, les versions récentes de FreeBSD
sed
permettent-r
d’augmenter la compatibilité avec GNUsed
).la source
bsdsed -i -e 's/a/A/'
n'est pas l' édition en place, c'est l'édition avec l'enregistrement de l'original avec un suffixe "-e" (testfile.txt-e
).Pour émuler
sed -i
pour un seul fichier de manière portable tout en évitant autant que possible les conditions de concurrence:Soit dit en passant, cela permet également de résoudre le problème éventuel:
sed -i
en fonction des autorisations accordées sur les répertoires et les fichiers,sed -i
un utilisateur peut remplacer un fichier qu’il n’a pas l’autorisation de modifier.Vous pouvez également faire des sauvegardes comme:
la source
Vous pouvez utiliser Vim en mode Ex:
1
sélectionner la première lignei
insérer du texte et une nouvelle lignex
sauver et fermerOu même, comme dans les commentaires, tout simplement vieux standard
ex
:la source
ex
, sauf que les implémentations ne sont pas obligées de prendre en charge plusieurs-c
drapeaux. Pour une portabilité définitive, je voudrais utiliserprintf '%s\n' 1i '<!DOCTYPE html>' . x | ex file