我正在编写一个基于 bash
declare -p
行为的 POSIX shell 函数,不同之处在于它针对的是 POSIX shell。
我设定了一些目标:
declare -p
所做的那样。我当前的问题在#4,但欢迎任何有关其他点的建议;-)
这是代码。第一个
awk
验证参数并生成用于更新 $@
的 shell 命令,然后使用 eval
进行处理。然后,第二个 awk
将打印带有单引号转义的变量声明:
编辑:根据@thatotherguy建议修复了代码
#!/bin/sh
declare_p() {
eval "$(
awk -v funcname="declare_p" '
BEGIN {
output = "set --"
for (i = 2; i < ARGC; i++) {
if (ARGV[i] ~ /^[[:alpha:]_][[:alnum:]_]*$/) {
output = output" "ARGV[i]" \042\044"ARGV[i]"\042"
} else {
print funcname": "ARGV[i]": not a valid identifier" > "/dev/stderr"
error = 1
# exit 1
}
}
print output
exit
}
END { if (error) print "false" }
' -- "$@"
)" # || return 1
awk -v rc="$?" '
BEGIN {
for (i = 2; i < ARGC; i += 2) {
gsub(/\047/,"\047\134\047\047",ARGV[i+1])
print ARGV[i] "=" "\047" ARGV[i+1] "\047"
}
exit rc
}
' -- "$@"
}
#!/bin/sh
var1=" a b "
var2="a'b"
var3="a
b"
var4="
"
declare_p var1 var2 var3 var4 var-x
echo "return code: $?"
输出:
declare_p: var-x: not a valid identifier # (stderr)
var1=' a b '
var2='a'\''b'
var3='a
b'
var4='
'
return code: 1
只是:
declare_p() {
while [ "$#" -ne 0 ]; do
if ! printf %s "$1" | grep -qx '[a-zA-Z_][a-zA-Z_0-9]*'; then
echo "declare_p: Invalid variable name: $1" >&2
return 1
fi
printf "%s='%s'\n" "$1" "$(
eval "printf %s \"\$$1\"" |
sed "s/'/'\\\\''/"
)"
shift
done
}
# unit test
var=$(seq 255 | xargs printf %02x\\n | xxd -r -p)
eval "$(var2="$var" ; declare_p var2)"
if [ "$var" = "$var2" ]; then echo FINE; fi
当然,您可以将
sed
和 grep
优化为一些神奇的 awk - 如果您想要性能使用不同的编程语言,我认为不值得花时间。
这是根据@thatotherguy 建议修正后的代码版本:
#!/bin/sh
declare_p() {
eval "$(
awk -v funcname="declare_p" '
function perror(str) { print str | "cat 1>&2" }
BEGIN {
output = "set --"
for (i = 2; i < ARGC; i++) {
if (ARGV[i] ~ /^[[:alpha:]_][[:alnum:]_]*$/) {
output = output" "ARGV[i]" \042\044"ARGV[i]"\042"
} else {
perror(funcname ": " ARGV[i] ": not a valid identifier")
error = 1
# exit 1
}
}
print output
exit
}
END { if (error) print "false" }
' -- "$@"
)" # || return 1
awk -v rc="$?" '
BEGIN {
for (i = 2; i < ARGC; i += 2) {
gsub(/\047/,"\047\134\047\047",ARGV[i+1])
print ARGV[i] "=" "\047" ARGV[i+1] "\047"
}
exit rc
}
' -- "$@"
}
第一个
awk
在参数无效的情况下强制 eval
以 false
命令结束;返回代码通过 awk
传递给第二个
-v rc="$?"
var1="123 456 789"
var2=" abc "
{
declare_p var1 var2
cat <<'EOF' # quoted heredocs don't expand anything so you can write your raw commands here
printf '<%s>\n' "$var1" "$var2"
EOF
} | ssh user@host sh
<123 456 789>
< abc >