使用 nix-shell 或 nix shell 在 Linux 64 上运行 MacOS sed
Posted
技术标签:
【中文标题】使用 nix-shell 或 nix shell 在 Linux 64 上运行 MacOS sed【英文标题】:Run MacOS sed on Linux 64 using nix-shell or nix shell 【发布时间】:2021-12-20 03:10:34 【问题描述】:回答关于 SO 的 sed 问题我经常遇到“适用于 linux 但不适用于 MacOS”的问题,是否可以将在 MacOS 上运行的 sed 版本加载到 nix shell 中?
目前使用 flakes,我可以使用以下方法获取最新的 gnused:
nix shell nixpkgs#gnused
有没有办法临时安装 BSD/MacOS 版本的 sed?
【问题讨论】:
使用 --posix 运行 gnu sed 我不认为在 Nixpkgs 中打包了另一个 sed 变体。可能没有必要。 你是potong
- 你不能问关于sed
的问题!!!苹果sed
的源码在这里,如果你想尝试编译它...opensource.apple.com/source/text_cmds/text_cmds-106/sed
我通过在我当前的 macOS 上运行 strings $(which sed)
得到了这一点(尽管他们的 sed
在 12 年内没有改变)并且它在顶部说这个 @(#)PROGRAM:sed PROJECT:text_cmds-106
未经测试,但 Dex 提供了一种“将 macos-sed 安装到 /usr/local/bin,带有 'macos-' 前缀”的方法,例如echo "ping" | macos-sed 's/ping/pong/'
。可能值得一看。
【参考方案1】:
不久前我研究了这个问题;也许你可以利用 我发现了什么。
Web 搜索显示在 BSD 之外对 FreeBSD sed
的需求很少,所以我
决定从
github
并在最近的 Debian 系统上构建和测试它。为此,我创建了
3 个文件(如下所列):
adapt/local.c
- 支持非 GNU 函数
adapt/local.h
- 同上头文件
Makefile
- 下载、生成所需文件、运行 1 或 2
测试套件;参考标头和目标附近的 cmets test
在我的系统上,可执行文件的构建没有错误。测试它使用
tests/multi_test.sh
我跑了
make test | tee multi_test.log | grep '^not ok' | tee multi_test.err.log
130 次测试中有 127 次成功,3 次失败:
not ok 69 7.1 # Print and file routines
not ok 75 7.7 # w results
not ok 97 8.21 # \ in y command
我认为,这些差异不会超出预期:#69
由sed -n l
的输出差异触发,#75 由差异触发
在/usr/share/dict/words
内容中(便携性有限的测试用例),
如果在 makefile 中使用 SHELL := /bin/bash
或使用 #97 则会消失
测试脚本中的 printf '%s\n' 'a\b(c'
而不是 echo 'a\b(c'
。更新 2021-11-24:#69 消失,例如
LANG=en make test | grep '^not ok'
,导致依赖于语言环境
库函数iswprint()
在process.c#lputs()
中为字符 0xA0..0xFF 返回零。 #75
只有/usr/share/dict/words
的前 200 行是
与测试用例作者使用的相同;我看不到
这背后的推理。 (结束更新)
还在待办事项清单上:
Makefile
的 *.names
变量是硬编码的,更好地创建
它们是动态的;然而,名称似乎很少改变
带有sed
历史的程序
支持ATF
tests/sed2_test.sh
的测试(目前被忽略)
支持在可执行文件中嵌入标识字符串 (__FBSDID
宏当前被忽略)而不是依赖于手册页中的日期
version
info
./Makefile
注意这里的食谱没有以通常的制表符作为前缀
但>
(在行首)充当make
运算符
(.RECIPEPREFIX = >
)。
# desc:
# Download, build, test FreeBSD sed (dated 2020-06-10) on GNU/Linux
# compat:
# dash 0.5.10 GNU make 4.2.1 GNU wget 1.20 GNU gcc 9.3.0 man 2.9
# ref:
# https://www.freebsd.org/cgi/man.cgi?sed
# https://github.com/freebsd/freebsd-src/tree/main/usr.bin/sed
# https://github.com/joshuarubin/wcwidth9
# files:
# Makefile adapt/local.c adapt/local.h
# howto:
# make download
# make all
# (optional) make download.tests download.regress.multitest.out test
# (optional) cp $(exe) /usr/local/bin/bsdsed
# (optional) cp $(man.1) /usr/local/man/man1/bsdsed.1
# note:
# Mind the $(wgetFlags) and $(CFLAGS)
SHELL := /bin/sh
wgetFlags ?= --no-verbose --wait=1
# $(call wgetCmd,subtarget-name)
define wgetCmd =
wget $(wgetFlags) --no-host-directories --directory-prefix=$($1.ldir) \
-- $(addprefix $($1.url),$($1.names))
endef
#
hdrs := defs.h extern.h
srcs := misc.c compile.c process.c main.c
hdrx := wcwidth9.h
srcx := local.c
objs := $(patsubst %.c,%.o,$(srcs) $(srcx))
# test scripts expect an executable named 'sed'
exe := sed
man.1 := $(exe).1
man.ps := $(exe).ps
binaries := $(exe) $(man.1) $(man.ps)
#
subtargets := wcwidth9 sed tests regress.multitest.out
dnldtargets := $(addprefix download.,$(subtargets))
#
wcwidth9.url := https://github.com/joshuarubin/wcwidth9/raw/master/
wcwidth9.names := $(hdrx)
wcwidth9.ldir := ./
#
sed.url := https://github.com/freebsd/freebsd-src/raw/master/usr.bin/sed/
sed.names := POSIX sed.1 $(srcs) $(hdrs)
sed.ldir := ./
tests.url := $(sed.url)tests/
tests.names := \
hanoi.sed inplace_race_test.sh legacy_test.sh math.sed \
multi_test.sh regress.G.out regress.P.out regress.b2a.out \
regress.bcb.out regress.c0.out regress.c1.out regress.c2.out \
regress.c3.out regress.hanoi.out regress.icase1.out \
regress.icase2.out regress.icase3.out regress.icase4.out \
regress.in regress.math.out regress.not.out regress.psl.out \
regress.s3.out regress.s4.out regress.s5.out regress.sg.out \
regress.sh regress.y.out sed2_test.sh
tests.ldir := ./tests/
regress.multitest.out.url := $(sed.url)tests/regress.multitest.out/
regress.multitest.out.names := \
1.1 1.2 1.3 1.4 1.4.1 1.5 1.6 1.7 1.8 1.9 1.10 1.11 1.12 1.13 \
1.14 1.15 1.16 1.17 1.18 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 \
2.10 2.11 2.12 2.13 2.14 2.15 2.16 2.17 2.18 2.19 2.20 2.21 \
2.22 2.23 3.1 3.2 3.3 3.4 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 5.1 \
5.2 5.3 5.4 5.5 5.6 5.7 5.8 6.1 6.2 6.3 6.4 6.5 6.6 7.1 7.2 \
7.3 7.4 7.5 7.6 7.7 7.8 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 \
8.10 8.11 8.12 8.13 8.14 8.15 8.16 8.17 8.18 8.19 8.20 8.21 \
8.22 8.23 9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9 9.10 9.11 9.12 \
9.13 9.14 9.15 9.16 9.17 9.18 9.19 9.20 9.21 9.22 9.23 9.24 \
9.25 9.26 9.27 9.28 9.29 9.30 9.31
regress.multitest.out.ldir := ./tests/regress.multitest.out/
.RECIPEPREFIX = >
.DELETE_ON_ERROR:
.PHONY: all clean realclean
all : $(binaries)
clean : ; rm -f -- $(objs) $(binaries)
realclean : clean
> rm -f -- local.c manpage.1 $(foreach T,$(subtargets),$(addprefix $($(T).ldir),$($(T).names)))
> rmdir --ignore-fail-on-non-empty -- \
$(patsubst %/,%,$(foreach T,$(subtargets),$(filter-out %. %./,$($(T).ldir))))
# notonbsd: enable modifications in extern.h and $(srcx)
# __FBSDID: don't embed RCS ID
$(objs) : CFLAGS += -Dnotonbsd -D__FBSDID\(s\)=
$(objs) : $(srcs) $(hdrs)
extern.h : adapt/local.h
> grep -q '^.ifdef\s*notonbsd' $@ || cat $@ $< > $@.tmp && mv -f -- $@.tmp $@ ;
local.c : adapt/local.c
> cp $< $@
local.o : $(hdrx)
main.o : CFLAGS += -D__unreachable=__builtin_unreachable
$(exe) : $(objs)
> $(LINK.c) -o $@ $^
> $(if $(DEBUG),,strip $@)
$(man.1) : manpage.1
> cp $< $@
%.ps : %.1
> man -l -t $< > $@
.PHONY : download.all $(dnldtargets) download
download.all : $(dnldtargets)
$(dnldtargets) :
> $(call wgetCmd,$(patsubst download.%,%,$@))
download : download.wcwidth9 download.sed
> mv -f sed.1 manpage.1
> touch adapt/local.h
.PHONY: test
# ! run after: make download.tests download.regress.multitest.out
# ! hint: make test | tee multi_test.log | grep '^not ok' | tee multi_test.err.log
# - set PATH so scripts invoke the new sed executable
# - run multi_test.sh (requires /usr/share/dict/words regress.multitest.out/*)
# - optionally run inplace_race_test.sh
# - ignore legacy_test.sh regress.* (require m4 regress.m4 hanoi.sed math.sed)
# - ignore sed2_test.sh (requires ATF, cf. https://github.com/freebsd/freebsd-src/tree/main/contrib/atf)
test : | /usr/share/dict/words
> cd $(patsubst %/,%,$(tests.ldir)); \
PATH="..:$$PATH"; \
$(SHELL) multi_test.sh \
$(if $(racetest),; $(SHELL) inplace_race_test.sh && rm -f file[0-9] file[0-9].prev)
./adapt/local.c
/* Support for non-GNU functions, cf. man.freebsd.org */
#ifdef notonbsd
#include <err.h>
#include <limits.h>
#include <regex.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include "defs.h"
#include "extern.h"
#include "wcwidth9.h" /* https://github.com/joshuarubin/wcwidth9 */
void
errc(int eval, int code, const char *fmt, ...)
va_list args;
va_start(args, fmt);
errno = code;
err(eval, fmt, args);
va_end(args);
char*
getprogname()
return (program_invocation_short_name);
int
wcwidth(wchar_t wc)
return wcwidth9(wc);
size_t
strlcpy(char *dst, const char *src, size_t dstsize)
return snprintf(dst, dstsize, "%s", src);
size_t
strlcat(char *dst, const char *src, size_t dstsize)
int dlen, slen, dslen, addlim;
dlen = strlen(dst);
slen = strlen(src);
dslen = dlen + slen;
addlim = (dstsize > dslen ? slen : dstsize - dlen - 1);
if ( addlim > 0 )
strncat(dst, src, addlim);
return dslen;
#endif /* notonbsd */
./adapt/local.h
/* To be appended to extern.h */
#ifdef notonbsd
extern char *program_invocation_short_name;
char *getprogname();
void errc(int eval, int code, const char *fmt, ...);
int wcwidth(wchar_t wc);
size_t strlcpy(char *dst, const char *src, size_t dstsize);
size_t strlcat(char *dst, const char *src, size_t dstsize);
#endif /* notonbsd */
更新于 2022-01-07
按照 Makefile
在 Debian 系统上构建 macOS sed
使用
与上面列出的 ./adapt/local.c
和 ./adapt/local.h
相同。在我的尽头
make download all
构建可执行文件没有错误,但警告
如果$(CFLAGS)
包含-O3
,则忽略返回值fchown
。
make download.TEST test
下载测试文件,生成并运行
test-edited.sh
(修改后的TEST/sed.test
)调整测试
参数并修复重定向问题。测试日志显示 113
115 个 (30+85) 个测试用例中的 (30+83) 个成功(test_error()
中的 30 个,
其余编号):
sed -n -e '0p' lines1
由 macOS sed
运行(和
FreeBSD sed
) 但 GNU sed
说“行地址 0 的使用无效”
测试 7.1 失败,即使行继续 char.s 被消除:
macOS 的l
命令sed
(和FreeBSD sed
)将反斜杠输出为\
但是POSIX.1-2017
(和 GNU sed
)说 \\
测试 7.7(涉及/usr/share/dict/words
)表明
应该运行等效的 FreeBSD sed
testcase #75(见上文)
针对本地文件,而不是测试作者生成的文件。
./Makefile
注意:配方前缀是>
(在行首),而不是制表符。
# desc:
# Download, build, test macOS sed (dated 2017-03-27) on GNU/Linux.
# compat:
# dash 0.5.10 GNU make 4.2.1 GNU wget 1.20.3 GNU gcc 9.3.0
# GNU sed 4.7 GNU coreutils 8.30 man 2.9.1
# ref:
# https://opensource.apple.com/source/text_cmds/text_cmds-106/sed/
# https://github.com/joshuarubin/wcwidth9
# see:
# Last sed manpage (dated May 10, 2005) captured by archive.org on Aug 8, 2017
# https://web.archive.org/web/20170808213955/https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/sed.1.html
# https://leancrew.com/all-this/2021/03/apple-and-links/
# https://opensource.apple.com/source/text_cmds/text_cmds-106/text_cmds.plist
# https://unix.stackexchange.com/questions/13711/differences-between-sed-on-mac-osx-and-other-standard-sed
# files:
# Makefile adapt/local.c adapt/local.h
# howto:
# make download
# make all
# (optional) make download.TEST test
# note:
# Mind the $(wgetFlags) and $(CFLAGS)
SHELL := /bin/sh
refsed ?= /usr/bin/sed --posix
wgetFlags ?= --no-verbose --wait=1
# $(call wgetCmd,subtarget-name)
define wgetCmd =
wget $(wgetFlags) --no-host-directories --directory-prefix=$($1.ldir) \
-- $(addprefix $($1.url),$($1.names))
endef
#
hdrs := defs.h extern.h
srcs := misc.c compile.c process.c main.c
hdrx := wcwidth9.h
srcx := local.c
objs := $(patsubst %.c,%.o,$(srcs) $(srcx))
exe := sed
#
sed.genfiles := $(exe) $(exe).1.gz $(exe).pdf
test.gendirs := ./sed.out/ ./nsed.out/
test.genfiles := test-edited.sh test.log test-diff.log $(addsuffix *,$(test.gendirs))
#
subtargets := wcwidth9 sed TEST
dnldtargets := $(addprefix download.,$(subtargets))
#
wcwidth9.url := https://github.com/joshuarubin/wcwidth9/raw/master/
wcwidth9.names := $(hdrx)
wcwidth9.ldir := ./
sed.url := https://opensource.apple.com/source/text_cmds/text_cmds-106/sed/
sed.names := POSIX sed.1 $(srcs) $(hdrs)
sed.ldir := ./
TEST.url := $(sed.url)TEST/
TEST.names := hanoi.sed math.sed sed.test
TEST.ldir := ./TEST/
.RECIPEPREFIX = >
.DELETE_ON_ERROR:
.PHONY: all testclean clean realclean
all : $(sed.genfiles)
testclean :
> rm -f -d -- $(test.genfiles) $(patsubst %/,%,$(test.gendirs))
clean : testclean
> rm -f -- $(objs) $(sed.genfiles)
realclean : clean
> rm -f -- local.c $(foreach T,$(subtargets),$(addprefix $($(T).ldir),$($(T).names)))
> rmdir --ignore-fail-on-non-empty -- $(patsubst %/,%, \
$(foreach T,$(subtargets),$(filter-out %. %./,$($(T).ldir))))
# notonbsd: enable modifications in extern.h and $(srcx)
# __FBSDID: don't embed RCS ID
$(objs) : CFLAGS += $(if $(DEBUG),,-s -O3) -Dnotonbsd -D__FBSDID\(s\)=
$(objs) : $(srcs) $(hdrs)
extern.h : adapt/local.h
> grep -q '^.ifdef\s*notonbsd' $@ || cat $@ $< > $@.tmp && mv -f -- $@.tmp $@ ;
local.c : adapt/local.c
> cp $< $@
local.o : $(hdrx)
main.o : CFLAGS += -D__unreachable=__builtin_unreachable
$(exe) : $(objs)
> $(LINK.c) $^ -o $@
%.1.gz : %.1
> gzip -fk $<
%.ps : %.1
> man -l -t $< > $@
%.pdf : %.ps
> ps2pdf $< $@
.PHONY : download.all $(dnldtargets) download
download.all : $(dnldtargets)
$(dnldtargets) :
> $(call wgetCmd,$(patsubst download.%,%,$@))
download : download.wcwidth9 download.sed
> touch adapt/local.h
.PHONY: test
# run after: make download.TEST
# notes:
# test 2.8: GNU sed says "invalid usage of line address 0"
# test 7.1 fails, even when line continuation char.s are eliminated:
# `l` command of macOS sed (and BSD sed) outputs backslash as '\'
# but POSIX.1-2017 (and GNU sed) says `\\`
test : test-diff.log
> printf '## test results in "%s"\n' '$<' 1>&2
test-diff.log : test.log
> - diff -c $(test.gendirs) > $@
# notes:
# `LANG=en`: cause test 7.1 not to output unicode/widechar
# creates $(test.gendirs)
# all tests in test_error() are supposed to produce error output
test.log : test-edited.sh
> LANG=en $(SHELL) $< 1>$@ 2>&1
> rm -f -- lines[1-4] script[1-2]
test-edited.sh : $(TEST.ldir)sed.test $(exe)
> $(refsed) \
-e '# main() : adjust test parameters' \
-e '/^.BASE=/ s,.*,BASE="$(refsed)",' \
-e '/^.TEST=/ s,.*,TEST="./$(exe)",' \
-e '# be silent' \
-e '/^.BSD=/ s,.*,BSD=0,' \
-e '/^.GNU=/ s,.*,GNU=0,' \
-e '/^.SUN=/ s,.*,SUN=0,' \
-e '# allow "sed --posix" as exename' \
-e '/^.tests / s,\(\$$[A-Z][A-Z]*\),"\1",g' \
-e '# comment out "diff -c"' \
-e '/^.diff -c/ s,^,#,' \
-e '# test_error(): fix stdin redirection' \
-e '/^.exec 0>&3 4>&1 5>&2/ s,0>&3,3<\&0,' \
-e '/^.exec 0>&3 1>&4 2>&5/ s,0>&3,0<\&3,' \
$< > $@
.PHONY : test-7.1-compare
# special case
test-7.1-compare : $(addsuffix .nolinecontinuation,$(wildcard $(addsuffix *_7.1,$(test.gendirs))))
> - diff -c $^
%.nolinecontinuation : %
> $(refsed) -e ':a' -e '/[^\\]\\$$/N; s/\\\n//; ta' < $< > $@
可能感兴趣:
$ apt-cache search '^freebsd'
ctfutils - FreeBSD CTF utilities
freebsd-buildutils - Utilities for building FreeBSD sources
freebsd-glue - Emulate a FreeBSD build environment
freebsd-manpages - Manual pages for a GNU/kFreeBSD system
freebsd-mk - FreeBSD makefile templates for bmake
libarchive-tools - FreeBSD implementations of 'tar' and 'cpio' and other archive tools
libfreebsd-glue-0 - FreeBSD glue environment (shared objects)
libipx2 - FreeBSD IPX address conversion support library
libsbuf6 - FreeBSD string buffer library
libutil-freebsd-9 - FreeBSD utility library
【讨论】:
谢谢。我也许可以用它来构建一个 nix 衍生产品。 @potong:已经有一段时间了,但我现在已经为 macOS 版本添加了一个 GNU makefile。 再次感谢,我会尝试将其改编为 nix 派生。以上是关于使用 nix-shell 或 nix shell 在 Linux 64 上运行 MacOS sed的主要内容,如果未能解决你的问题,请参考以下文章
我可以复制nix-build与nix-shell和cabal构建的内容吗?
清理丑陋的所见即所得 HTML 代码? Python 或 *nix 实用程序