la commande sed avec l'option-i (édition en place) fonctionne très bien sur Ubuntu mais pas sur Mac [dupliquer]

cette question a déjà une réponse ici:

Je ne sais rien sur Sed mais j'ai besoin de cette commande (qui fonctionne très bien sur Ubuntu) pour travailler sur un Mac OSX:

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

j'obtiens:

sed: 1: "/etc/hosts": extra characters at the end of h command
63
demandé sur mklement0 2013-05-25 07:03:08

4 réponses

Navires Ubuntu avec GNU sed , où le suffixe pour l'option -i est facultatif. OS X est livré avec BSD sed , où le suffixe est obligatoire. Essayez sed -i ''

116
répondu microtherion 2013-05-25 03:15:19

À compléter", 1519480920" microtherion de l'utile, du point de réponse :

  • avec une solution portable
  • avec des informations de fond

tl; dr :

l'équivalent de ce GNU sed (standard sur la plupart Linux distros) commande:

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

est ce BSD / macOS sed commande:

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

Avec BSD/macOS sed , les commandes suivantes faire pas travail 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 de tous le les différences entre GNU sed et BSD/mac os sed , voir cette réponse de la mine.

Portable "approche de 1519590920" :

Note: Portable signifie ici que la commande fonctionne avec les deux implémentations discutées. Il n'est pas portable dans un POSIX sens, parce que l'option -i 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 les solutions de rechange, y compris une solution conforme à POSIX, voir cette réponse connexe de la mienne.


informations générales

In GNU sed (standard sur la plupart des distributions Linux) et BSD / macOS sed , les -i option, qui exécute mise à jour en place [1] de ses fichiers d'entrée, accepte une option-argument qui spécifie ce que suffixe (extension de nom de fichier) à utiliser pour le fichier de sauvegarde du fichier mis à jour .

par exemple, dans les deux implémentations , ce qui suit conserve 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 avec GNU sed le suffixe argument est optionnel , alors qu'avec BSD/macOS "1519640920 sed il est obligatoire , la syntaxe ci-dessus fonctionne avec à la fois implémentations, parce que directement attenant l'option-argument ( .bak ) à l'option ( -i ) - -i.bak , par opposition à -i .bak - fonctionne à la fois comme un facultatif et un obligatoire option-argument :

  • syntaxe -i.bak est le seulement forme qui fonctionne pour un optionnel option-argument.
  • syntaxe -i.bak aussi fonctionne comme un obligatoire option-argument, comme un alternative à -i .bak , c'est à dire, en spécifiant l'option et son argument séparément .

ne spécifiant pas de suffixe - ce qui est souvent le cas - signifie que pas de fichier de sauvegarde doit être conservé, et c'est où l'incompatibilité se pose :

  • avec GNU sed , ne pas spécifier de suffixe signifie simplement utiliser -i par lui-même .

  • avec BSD / macOS sed , sans suffixe signifie la chaîne vide comme suffixe-obligatoire, et pour technique " argument : c'est-à-dire, -i '' pas -i'' .

-i'' ne fonctionne pas, car à sed il est impossible de le distinguer de juste -i , parce que le shell effectivement supprime les citations vides (il concaténate -i et '' et supprime les citations avec la fonction syntaxique), et passe juste -i dans les deux cas.

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

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

's/foo/bar/' - destiné au sed script (commande) - est maintenant interprété comme le suffixe , et le mot file est interprété comme le script.

L'interprétation d'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 argument, et non comme -e option de Sed (qui peut être utilisé pour spécifier multiple commandes, si nécessaire).

En conséquence, au lieu de ne pas conserver de sauvegarde, vous obtenez un fichier de sauvegarde avec le suffixe -e .

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

que la création accidentelle de ces fichiers de sauvegarde passe facilement inaperçue est l'explication la plus probable pour réponse incorrecte de Crt et cette réponse incorrecte à une question similaire ayant reçu tant de votes positifs (en date de cette écriture).


[1] à proprement parler, un le fichier temporaire est créé dans les coulisses, puis remplace le fichier original; cette approche peut être problématique: voir la moitié inférieure de cette réponse de la mienne.

41
répondu mklement0 2017-08-22 12:09:42

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.
19
répondu Diego Torres Milano 2013-05-25 03:14:34

dans 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

alors, si votre script doit être portable, en fonction de votre système D'exploitation, 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
2
répondu jcarballo 2017-06-30 12:27:19