Che*_*eng 31 scripting sed executable env
输入/usr/bin/env sed -f
终端工作。
但如果将其用作shebang,
#!/usr/bin/env sed -f
s/a/b/
Run Code Online (Sandbox Code Playgroud)
脚本将无法执行:
/usr/bin/env: sed -f: No such file or directory
Run Code Online (Sandbox Code Playgroud)
我有点相信它与-f有关。但是如何解决这个问题呢?
Gil*_*il' 35
可移植地,您不能在#!
一行上放置多个参数。这意味着只有一个完整的路径和一个参数(例如#!/bin/sed -f
或#!/usr/bin/sed -f
),或者#!/usr/bin/env
没有参数给解释器。
获取可移植脚本的解决方法是使用#!/bin/sh
shell 包装器,将 sed 脚本作为命令行参数传递。请注意,这不是 POSIX 认可的(多指令脚本必须-e
为每个指令编写一个单独的参数以实现可移植性),但它适用于许多实现。
#!/bin/sh
exec sed '
s/a/b/
' "$@"
Run Code Online (Sandbox Code Playgroud)
对于长脚本,使用 heredoc 可能更方便。Heredoc 的一个优点是你不需要引用里面的单引号,如果有的话。一个主要的缺点是脚本在其标准输入上被提供给 sed,有两个恼人的后果。某些版本的 sed 需要-f /dev/stdin
而不是-f -
,这是可移植性的问题。更糟糕的是,脚本不能充当过滤器,因为标准输入是脚本而不能是数据。
#!/bin/sh
exec sed -f - -- "$@" <<'EOF'
s/a/b/
EOF
Run Code Online (Sandbox Code Playgroud)
可以通过有用地使用cat
. 由于这会将整个脚本再次放在命令行上,因此它不符合 POSIX 标准,但在实践中很大程度上是可移植的。
#!/bin/sh
exec sed "$(cat <<'EOF')" -- "$@"
s/a/b/
EOF
Run Code Online (Sandbox Code Playgroud)
另一种解决方法是编写一个脚本,该脚本可以同时被 sh 和 sed 解析。这是便携式的,相当高效,只是有点丑陋。
#! /bin/sh
b ()
{
x
}
i\
f true; then exec sed -f "$0" "$@"; fi
: ()
# sed script starts here
s/a/b/
Run Code Online (Sandbox Code Playgroud)
说明:
b
;只要函数在语法上格式良好(特别是,你不能有一个空函数),内容并不重要。然后如果为真(即始终),则sed
在脚本上执行。()
标签,然后是一些格式良好的输入。然后是一个i
命令,它没有任何效果,因为它总是被跳过。最后是()
标签,后跟脚本的有用部分。小智 9
从 GNU coreutils v8.30 开始,您可以执行以下操作:
#!/usr/bin/env -S sed -f
Run Code Online (Sandbox Code Playgroud)
在最近的(2018年4月20日)中加入此功能提交到env.c
在GNU coreutils软件包,其添加的-S
或--split-string
选项。
从env
手册页:
OPTIONS
-S/--split-string usage in scripts
The -S option allows specifing multiple parameters in a script.
Running a script named 1.pl containing the following first line:
#!/usr/bin/env -S perl -w -T
Will execute perl -w -T 1.pl .
Without the '-S' parameter the script will likely fail with:
/usr/bin/env: 'perl -w -T': No such file or directory
See the full documentation for more details.
Run Code Online (Sandbox Code Playgroud)
GNU coreutils 手册中提供了更多示例。
如果您还使用-v
详细输出选项,您可以准确地看到如何
env
拆分参数字符串:
在my_sed_script.sed
:
#!/usr/bin/env -vS sed -f
s/a/b/
Run Code Online (Sandbox Code Playgroud)
执行:
$ ./my_sed_script.sed
split -S: ‘sed -f’
into: ‘sed’
& ‘-f’
executing: sed
arg[0]= ‘sed’
arg[1]= ‘-f’
arg[2]= ‘./my_sed_script.sed’
Run Code Online (Sandbox Code Playgroud)
注意:这仅适用于使用 的shebang /usr/bin/env
,这
--split-string
是 GNU 的一个特性env
。
根据操作系统的不同,shebang (#!) 有各种不兼容的实现。有些正在构建完整的参数列表,有些正在保留命令路径并将所有剩余参数作为一个单独的参数,有些忽略所有参数并仅传递命令路径,最后,有些将整个字符串作为单个传递命令。你似乎属于后一种情况。