Musím svůj sed -i příkaz pro in-place editaci pracovat jak s GNU sed a BSD / OSX sed

hlasů
41

Mám Makefile (vyvinutý pro gmake v systému Linux), že jsem se pokouší přístavu do OSX, ale vypadá to, že sed nechce spolupracovat. To, co dělám, je použít GCC k autogenerate závislost soubory, a poté vyladit jim trochu pomocí sed. Příslušná část makefile:

$(OBJ_DIR)/%.d: $(SRC_DIR)/%.cpp
  $(CPPC) -MM -MD $< -o $@
  sed -i 's|\(.*\)\.o:|$(OBJ_DIR)/\1.o $(OBJ_DIR)/\1.d $(TEST_OBJ_DIR)/\1_utest.o:|' $@

I když to běží s pod GNU / Linuxem bez problémů, jsem si chyby, jako v následujícím, kdy se pokouší navázat na OSX:

sed: 1: test/obj/equipmentConta ...: undefined label 'est/obj/equipmentContainer_utest.d'
sed: 1: test/obj/dice_utest.d: undefined label 'est/obj/dice_utest.d'
sed: 1: test/obj/color-string_u ...: undefined label 'est/obj/color-string_utest.d'

Mohlo by se zdát, jako sed je odsekne znak, ale nevidím řešení.

Položena 23/02/2010 v 19:07
zdroj uživatelem
V jiných jazycích...                            


7 odpovědí

hlasů
58

OS Xsed stará o -iargument, jinak se Linux verze.

Můžete vygenerovat příkaz, který by mohl „fungovat“ pro oba přidáním -etakto:

#      vv
sed -i -e 's|\(.*\)\.o:|$(OBJ_DIR)/\1.o $(OBJ_DIR)/\1.d $(TEST_OBJ_DIR)/\1_utest.o:|' $@

OS X sed -iinterpretuje další věc poté, co -ijako příponu souboru pro záložní kopie na úpravy na místě. (Verze Linux dělá jen to, pokud není mezera mezi -ia rozšíření). Je zřejmé, že strana ovlivnit využití je to, že budete mít záložní soubor se -ejako rozšíření, které vám nemusí chtít. Naleznete další odpovědi na tuto otázku pro více informací a čistší přístupy, které mohou být použity místo.

Chování vidíte, je to proto, že OS X sedspotřebuje s|||jako prodloužení pak interpretuje (!) Další argument jako příkaz - v tomto případě se začíná t, který seduznává jako povel pobočka-to-štítku v očekávání cílové označení jako argument - proto došlo k chybě vidíte.

Máte-li vytvořit soubor testmůžete reprodukovat došlo k chybě:

$ sed -i 's|x|y|' test
sed: 1: "test": undefined label 'est'
Odpovězeno 23/02/2010 v 22:41
zdroj uživatelem

hlasů
43

Actally .. dělá

sed -i -e "s/blah/blah/" files

není to, co můžete očekávat v OS X buď .. místo toho se vytvoří záložní soubory s příponou „-e“.

Správné OS je

sed -i "" -e "s/blah/blah/" files
Odpovězeno 10/03/2010 v 22:06
zdroj uživatelem

hlasů
18

Aktuálně přijímanou odpovědí je chybné ve dvou velmi důležitých ohledech.

  1. BSD sed (verze OSX), je -emožnost je interpretován jako příponu souboru, a proto vytvoří záložní soubor s -e příponou.

  2. Testování pro jádro Darwin, jak je navrženo není spolehlivý přístup ke křížové univerzální řešení od GNU nebo BSD sed mohou být přítomny na libovolném počtu systémů.

Mnohem spolehlivější testy by bylo jednoduše testovat --versionmožnosti, které se nachází pouze v GNU verzi sed.

sed --version >/dev/null 2>&1

Jakmile je správná verze SED je určena, pak můžeme spustit příkaz v jeho správné syntaxi.

GNU sed syntaxi -i:

sed -i -- "$@"

BSD sed syntaxi -i:

sed -i "" "$@"

A konečně dát to všechno dohromady do funkce křížové platformě vykonat v místě editovat sed pochválit:

sedi () {
    sed --version >/dev/null 2>&1 && sed -i -- "$@" || sed -i "" "$@"
}

Příklad použití:

sedi 's/old/new/g' 'some_file.txt'

Toto řešení bylo testováno na OSX, Ubuntu, FreeBSD, Cygwin, CentOS, Red Hat Enterprise & MSYS.

Odpovězeno 26/07/2016 v 16:22
zdroj uživatelem

hlasů
11

To není tak docela odpověď na tuto otázku, ale je možné získat linux-ekvivalent chování prostřednictvím brew install gnu-sed --with-default-names

Odpovězeno 22/12/2014 v 02:11
zdroj uživatelem

hlasů
9

Přišel jsem v celé této problematiky, jakož i myšlenka následující řešení:

darwin=false;
case "`uname`" in
  Darwin*) darwin=true ;;
esac

if $darwin; then
  sedi="/usr/bin/sed -i ''"
else
  sedi="sed -i"
fi

$sedi 's/foo/bar/' /home/foobar/bar

Pracuje pro mě ;-), YMMV

I pracovat v týmu s více operačními systémy, kde PPL stavět na Windows, Linux a OS X. Někteří uživatelé OS X si stěžoval, protože dostal další chybu - měli port GNU sed instalovány tak jsem musel zadat úplnou cestu.

Odpovězeno 06/01/2014 v 14:58
zdroj uživatelem

hlasů
6

Martin Clayton užitečné odpovědi poskytuje dobré vysvětlení tohoto problému [1] , ale řešení, které - jak se uvádí - má potenciálně nežádoucí vedlejší účinky.

Zde jsou vedlejší účinek bez řešení :

Námitka : Řešení -iproblému syntaxe sám, jak je uvedeno níže, nemusí stačit, protože existuje mnoho dalších rozdílů mezi GNU seda BSD / MacOS sed(pro komplexní diskusi, vidět tuto odpověď dolu).


Řešením se -i: Vytvořit záložní soubor dočasně , pak ho uklidit:

S non-prázdné příponou (backup-file příponou) option-argumentu (hodnota, která není prázdný řetězec ), vy můžete použít -itakovým způsobem, který pracuje jak s BSD / MacOS seda GNU sedtím, že se přímo připojí příponu na -ivolba .

To může být využito k vytvoření záložního souboru dočasně které můžete uklidit hned:

sed -i.bak 's/foo/bar/' file && rm file.bak

Je zřejmé, že pokud si chcete zachovat zálohu, jednoduše vynechat && rm file.bakčást.


Řešením, které je POSIX kompatibilní, pomocí dočasného souboru a mv:

Pokud pouze jediný soubor, který chcete upravit na místě, volba může být vynecháno , aby se předešlo neslučitelnosti.-i

Máte-li omezit svůj sedscénář a další možnosti POSIX-kompatibilní funkcí , následující je plně přenosné řešení (všimněte si, že -ije není POSIX kompatibilní ).

sed 's/foo/bar' file > /tmp/file.$$ && mv /tmp/file.$$ file
  • Tento příkaz jednoduše zapisuje změny do dočasného souboru a v případě, že sedpříkaz uspěje ( &&), nahradí původní soubor s dočasným jeden.

    • Pokud chcete zachovat původní soubor jako záložní, přidat další mvpříkaz, který přejmenuje původní první.
  • Caveat : Podstatnější je, že to je to, co -idělá taky, kromě toho, že se snaží zachovat oprávnění a rozšířené atributy (MacOS) z původního souboru; Nicméně, pokud se původní soubor je symbolickým odkazem , jak toto řešení a -inahradí symlink s pravidelným souborem .
    Podívejte se na dolní polovinu této odpovědi mé další podrobnosti o tom, jak -ifunguje.


[1] Pro bližší vysvětlení do hloubky, viz tuto odpověď dolu.

Odpovězeno 03/07/2017 v 03:12
zdroj uživatelem

hlasů
1

Já jsem opravil řešení odeslaný @thecarpy:

Zde je správné řešení pro cross-platform sed -i:

sedi() {
  case $(uname) in
    Darwin*) sedi=('-i' '') ;;
    *) sedi='-i' ;;
  esac

  LC_ALL=C sed "${sedi[@]}" "$@"
}
Odpovězeno 02/03/2016 v 20:10
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more