165 votes

la commande sed avec l'option -i (édition en place) fonctionne bien sur Ubuntu mais pas sur Mac

Je ne connais rien à Sed mais j'ai besoin que cette commande (qui fonctionne bien sur Ubuntu) fonctionne sur un Mac OSX :

sed -i "/ $domain .*#drupalpro/d" /etc/hosts

J'y vais :

sed: 1: "/etc/hosts": extra characters at the end of h command

219voto

microtherion Points 3363

Ubuntu est livré avec GNU sed où le suffixe de l'élément -i est facultative. OS X est livré avec BSD sed où le suffixe est obligatoire. Essayez sed -i ''

169voto

mklement0 Points 12597

Pour compléter La réponse utile et précise de microtherion :

  • avec une solution portable
  • avec des informations de fond

tl;dr :

L'équivalent de ceci GNU sed (standard sur la plupart des Linux distros) :

sed -i    's/foo/bar/' file

c'est ceci BSD/macOS sed comando:

sed -i '' 's/foo/bar/' file  # Note the '' as a *separate argument*

Avec BSD/macOS sed les commandes suivantes faire no travail pas du tout ou pas comme prévu :

sed -i    's/foo/bar/' file  # Breaks; script is misinterpreted as backup-file suffix
sed -i''  's/foo/bar/' file  # Ditto
sed -i -e 's/foo/bar/' file  # -e is misinterpreted as backup-file suffix

Pour une discussion sur tous les différences entre GNU sed et BSD/macOS sed voir cette réponse de la mienne.

Approche portable :

Note : Portable ici signifie que la commande fonctionne avec les deux implémentations discutées. Elle n'est pas portable dans une POSIX sens, car le site -i L'option n'est pas conforme à POSIX .

# Works with both GNU and BSD/macOS Sed, due to a *non-empty* option-argument:
# Create a backup file *temporarily* and remove it on success.
sed -i.bak 's/foo/bar/' file && rm file.bak

Pour une explication, voir ci-dessous ; pour des solutions alternatives, y compris une solution conforme à POSIX, voir cette réponse connexe de la mienne.


Informations générales

Sur GNU sed (standard sur la plupart des distros Linux) et BSD/macOS sed , le site -i qui effectue mise à jour sur place [1] de ses fichiers d'entrée, accepte un option-argument qui précise ce que suffixe (extension du nom de fichier) à utiliser pour l'option fichier de sauvegarde du fichier en cours de mise à jour .

Par exemple, dans ambos les implémentations suivantes conservent le fichier original, file comme fichier de sauvegarde file.bak :

sed -i.bak 's/foo/bar/' file  # Keep original as 'file.bak'; NO SPACE between -i and .bak

Même si con GNU sed l'argument suffixe est en option alors qu'avec BSD/macOS sed c'est obligatoire la syntaxe ci-dessus fonctionne avec ambos car directement adjacente à l'argument d'option ( .bak ) à l'option ( -i ) - -i.bak par opposition à -i .bak - fonctionne à la fois comme un en option et un obligatoire option-argument :

  • Syntaxe -i.bak est le seulement qui fonctionne pour un en option option-argument.
  • Syntaxe -i.bak également fonctionne comme un obligatoire en tant qu'argument d'option, comme un alternative à -i .bak c'est-à-dire en spécifiant l'option et son argument séparément .

Ne pas spécifier de suffixe - ce qui est souvent le cas - signifie que pas de fichier de sauvegarde doit être conservé, et c'est là que l'incompatibilité survient :

  • Avec GNU sed si l'on ne spécifie pas de suffixe, cela signifie que l'on utilise simplement l'option -i par lui-même .

  • Avec BSD/macOS sed ne pas spécifier de suffixe, c'est spécifier la chaîne vide comme suffixe - obligatoire - et for technique Pour des raisons de sécurité, la chaîne vide ne peut être transmise qu'en tant qu'élément d'information. séparé argument c'est-à-dire, -i '' no -i'' .

-i'' ne fonctionne pas, car pour sed il n'est pas possible de le distinguer d'un simple -i parce que le coquille efficacement supprime les guillemets vides (il concatène -i y '' et supprime les guillemets avec la fonction syntaxique), et passe juste -i en ambos cas.

Avec (effectivement) seulement -i spécifié, c'est le suivant qui est interprété comme l'argument d'option :

sed -i 's/foo/bar/' file # BREAKS with BSD/macOS Sed

's/foo/bar/' - destiné à la Sed script (commande) - est maintenant interprété comme l'option suffixe et le mot file est interprété comme le script.
Interpréter un tel mot comme script conduit alors à un message d'erreur obscur tel que
sed: 1: "file": invalid command code f ,
parce que le f est interprété comme une commande Sed (fonction).

De même, avec :

sed -i -e 's/foo/bar/' file # CREATES BACKUP FILE 'file-e'

-e est interprété comme le suffixe et NON comme l'argument de Sed -e option (qui peut être utilisé pour spécifier multiple commandes, si nécessaire).
En conséquence, au lieu de ne garder AUCUNE sauvegarde, vous obtenez un fichier de sauvegarde avec le suffixe -e .

Le fait que cette commande ne fonctionne pas comme prévu est moins évident, car la mise à jour en place réussit, étant donné que l'exigence syntaxique de l'argument suffixe est satisfaite par la commande -e argument.

Que la création accidentelle de ces fichiers de sauvegarde passe facilement inaperçue est l'explication la plus probable pour Réponse incorrecte du Crt y cette réponse incorrecte à une question similaire ayant reçu autant de votes positifs (au moment où nous écrivons ces lignes).


[1] Strictement parlant, un fichier temporaire est créé dans les coulisses, et ensuite remplace le fichier d'origine ; cette approche peut être problématique : voir la moitié inférieure de la page cette réponse de la mienne.

24voto

dtmilano Points 26472

L'homme est votre ami.

OS X

 -i extension
         Edit files in-place, saving backups with the specified extension.
         If a zero-length extension is given, no backup will be saved.  It
         is not recommended to give a zero-length extension when in-place
         editing files, as you risk corruption or partial content in situ-
         ations where disk space is exhausted, etc.

7voto

jcarballo Points 1662

Sous OS X, vous pouvez utiliser la version GNU de sed : gsed .

# if using brew
brew install gnu-sed

#if using ports
sudo port install gsed

Ensuite, si votre script doit être portable, en fonction de votre OS vous pouvez définir quelle commande utiliser.

SED=sed
unamestr=`uname`
if [[ "$unamestr" == "Darwin" ]] ; then
    SED=gsed
    type $SED >/dev/null 2>&1 || {
        echo >&2 "$SED it's not installed. Try: brew install gnu-sed" ;
        exit 1;
    }
fi
# here your sed command, e.g.:
$SED -i "/ $domain .*#drupalpro/d" /etc/hosts

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X