Existe-t-il un appel de sed
à faire une édition sur place sans sauvegardes qui fonctionne à la fois sous Linux et Mac? Bien que le BSD sed
fourni avec OS X semble avoir besoin de sed -i '' …
, the GNU sed
Les distributions Linux viennent généralement avec interprètent les guillemets comme un nom de fichier d'entrée vide (au lieu de l'extension de sauvegarde), et ont besoin de sed -i …
au lieu.
Existe-t-il une syntaxe de ligne de commande qui fonctionne avec les deux types, de sorte que je puisse utiliser le même script sur les deux systèmes?
Si vous voulez vraiment utiliser simplement sed -i
De la manière "facile", ce qui suit fonctionne avec GNU et avec BSD/Mac sed
:
sed -i.bak 's/foo/bar/' filename
Notez le manque d'espace et le point.
Preuve:
# GNU sed
% sed --version | head -1
GNU sed version 4.2.1
% echo 'foo' > file
% sed -i.bak 's/foo/bar/' ./file
% ls
file file.bak
% cat ./file
bar
# BSD sed
% sed --version 2>&1 | head -1
sed: illegal option -- -
% echo 'foo' > file
% sed -i.bak 's/foo/bar/' ./file
% ls
file file.bak
% cat ./file
bar
Évidemment, vous pouvez alors simplement supprimer les fichiers .bak
.
Cela fonctionne avec GNU sed, mais pas sous OS X:
sed -i -e 's/foo/bar/' target.file
sed -i'' -e 's/foo/bar/' target.file
Cela fonctionne sous OS X, mais pas avec GNU sed:
sed -i '' -e 's/foo/bar/' target.file
Sur OS X vous
sed -i -e
puisque l’extension du fichier de sauvegarde serait définie sur -e
sed -i'' -e
pour les mêmes raisons: il faut un espace entre -i
et ''
.Quand je suis sur OSX, j'installe toujours la version GNU sed via Homebrew, pour éviter les problèmes de scripts, car la plupart des scripts ont été écrits pour des versions GNU sed.
brew install gnu-sed --with-default-names
Ensuite, votre BSD sed sera remplacé par GNU sed.
Alternativement, vous pouvez installer sans default-names, mais ensuite:
Il n'y a aucun moyen de le faire fonctionner.
Une solution consiste à utiliser un fichier temporaire tel que:
TMP_FILE=`mktemp /tmp/config.XXXXXXXXXX`
sed -e "s/abc/def/" some/file > $TMP_FILE
mv $TMP_FILE some/file
Cela fonctionne à la fois
Comme Noufal Ibrahim demande, pourquoi ne pouvez-vous pas utiliser Perl? Tout Mac aura Perl, et très peu de distributions Linux ou BSD n'incluent aucune version de Perl dans le système de base. BusyBox (qui fonctionne comme GNU/Linux pour -i
, sauf qu'aucune extension de sauvegarde ne peut être spécifiée).
Comme ismail recommande,
Puisque Perl est disponible partout, je ne fais que
Perl -pi -e s,foo,bar,g target.file
et cela semble être une meilleure solution dans presque tous les cas que les scripts, les alias ou autres solutions palliatives pour traiter l'incompatibilité fondamentale de sed -i
entre GNU/Linux et BSD/Mac.
Réponse: Non.
La réponse initialement acceptée ne fait pas ce qui est demandé (comme indiqué dans les commentaires). (J'ai trouvé cette réponse en cherchant la raison pour laquelle un file-e
Apparaît "de manière aléatoire" dans mes répertoires.)
Il n'y a apparemment aucun moyen d'obtenir que sed -i
Fonctionne de manière cohérente à la fois sur MacOS et Linuces.
Ma recommandation, pour ce que cela vaut, n'est pas de mettre à jour sur place avec sed
(qui a des modes de défaillance complexes), mais de générer de nouveaux fichiers et de les renommer par la suite. En d'autres termes: évitez -i
.
L'option -i
Ne fait pas partie de POSIX Sed . Une méthode plus portable consisterait à utiliser Vim en mode Ex:
ex -sc '%s/alfa/bravo/|x' file
%
Sélectionne toutes les lignes
s
replace
x
enregistrer et fermer
Voici une autre version qui fonctionne sous Linux et macOS sans utiliser eval
et sans avoir à supprimer les fichiers de sauvegarde. Il utilise des tableaux Bash pour stocker les paramètres sed
, ce qui est plus propre que d'utiliser eval
:
# Default case for Linux sed, just use "-i"
sedi=(-i)
case "$(uname)" in
# For macOS, use two parameters
Darwin*) sedi=(-i "")
esac
# Expand the parameters in the actual call to "sed"
sed "${sedi[@]}" -e 's/foo/bar/' target.file
Cela ne crée pas de fichier de sauvegarde, ni de fichier avec des guillemets ajoutés.
La réponse de Steve Powell est tout à fait correct, consulter la page MAN pour sed sur OSX et Linux (Ubuntu 12.04) met en évidence l'in-compatibilité dans l'utilisation sed 'in-situ' à travers les deux systèmes d'exploitation.
JFYI, il ne devrait y avoir aucun espace entre le -i et les guillemets (qui désignent une extension de fichier vide) en utilisant la version Linux de sed, donc
#Linux
sed -i""
et
#OSX (notice the space after the '-i' argument)
sed -i ""
J'ai résolu ce problème dans un script en utilisant une commande alias'd et la sortie du nom du système d'exploitation de ' uname ' dans un bash 'if'. Tenter de stocker des chaînes de commande dépendantes du système d’exploitation dans des variables a été aléatoire lors de l’interprétation des guillemets. L'utilisation de ' shopt -s expand_aliases ' est nécessaire pour développer/utiliser les alias définis dans votre script. l'utilisation de shopt est traitée ici .
J'ai rencontré ce problème. La seule solution rapide a été de remplacer le sed dans mac par la version gnu:
brew install gnu-sed
Si vous devez utiliser sed
sur place dans un script bash
, et que vous ne voulez PAS que celui-ci résulte avec des fichiers .bkp, vous avez un moyen de détecter le système d'exploitation ( dire, en utilisant ostype.sh ), - alors le hack suivant avec le bash
shell intégré eval
devrait fonctionner:
OSTYPE="$(bash ostype.sh)"
cat > myfile.txt <<"EOF"
1111
2222
EOF
if [ "$OSTYPE" == "osx" ]; then
ISED='-i ""'
else # $OSTYPE == linux64
ISED='-i""'
fi
eval sed $ISED 's/2222/bbbb/g' myfile.txt
ls
# GNU and OSX: still only myfile.txt there
cat myfile.txt
# GNU and OSX: both print:
# 1111
# bbbb
# NOTE:
# if you just use `sed $ISED 's/2222/bbbb/g' myfile.txt` without `eval`,
# then you will get a backup file with quotations in the file name,
# - that is, `myfile.txt""`
Vous pouvez utiliser une éponge. Sponge est un ancien programme unix, qui se trouve dans le paquetage moreutils (à la fois sous ubuntu et probablement debian, et en homebrew sous mac).
Il va mettre en mémoire tampon tout le contenu du canal, attendre que le canal soit fermé (ce qui signifie probablement que le fichier d'entrée est déjà fermé), puis écraser:
De la page de manuel :
Synopsis
sed '...' file | grep '...' | fichier éponge
Ce qui suit fonctionne pour moi sous Linux et OS X:
sed -i' ' <expr> <file>
par exemple. pour un fichier f
contenant aaabbaaba
sed -i' ' 's/b/c/g' f
donne aaaccaaca
sous Linux et Mac. Notez qu'il existe une chaîne entre guillemets contenant un espace, avec sans espace entre les -i
et la chaîne. Les guillemets simples ou doubles fonctionnent tous les deux.
Sous Linux, j'utilise bash
version 4.3.11 sous Ubuntu 14.04.4 et sous Mac version 3.2.57 sous OS X 10.11.4 El Capitan (Darwin 15.4.0).