例如:
srcdir = ../libc # Src directory
prefix = /usr/local // Installation path
第一行来自 makefile,第二行来自config.make
.
我需要在 shell 脚本中访问变量$srcdir
和$prefix
。
我发现的一个解决方案是将所有内容都剪切` = `
到and和and do`=`
之后的部分。#
//
eval
还有其他简单可靠的解决方案吗?
我在#!/bin/sh
.
答案1
你永远不应该尝试在 shell 脚本中解析外语。您总是会遇到一些意想不到的警告,并且尝试适应所有情况只会成为一场噩梦。
相反,使用本机解释器来解析它并为您提供您想要的内容。
getmakevar() {
makefile="$1"
var="$2"
make getmakevar -f - <<EOI
include $makefile
getmakevar:
@echo \$($var)
EOI
}
它符合 POSIX 标准,并且可以处理任何和所有可能的 makefile 格式(只要它是有效的 gnu make)
# cat Makefile
bar=baz
myvar = /foo/$(bar)
# getmakevar Makefile myvar
/foo/baz
答案2
我做了一个纯POSIX sh版本。我喜欢它的地方:
- 完全基于 shell(除了 printf 之外,不调用外部命令)
- 通用(shell函数可复用)
- 它将定义导入到当前环境中。
我不喜欢的事情:
- 使用评估。我试图避免它,但有必要在不对其进行硬编码的情况下进行定义。我正在验证该名称是否合理并引用该值。这应该是安全的,但我不能 100% 确定它是安全的。
- POSIX sh 很丑陋。
- POSIX sh 中的函数没有局部变量。
嗯,这是:
#!/bin/sh
trim_left() {
_str=$1 _chrs=$2
while [ "$_chrs" ]; do
_chr=${_chrs%"${_chrs#?}"}
while [ "${_str%"${_str#?}"}" = "$_chr" ]; do
_str=${_str#?}
done
_chrs=${_chrs#?}
done
printf %s "$_str"
}
trim_right() {
_str=$1 _chrs=$2
while [ "$_chrs" ]; do
_chr=${_chrs%"${_chrs#?}"}
while [ "${_str#"${_str%?}"}" = "$_chr" ]; do
_str=${_str%?}
done
_chrs=${_chrs#?}
done
printf %s "$_str"
}
trim_comment() {
_str=$1 _marker=$2
printf %s "${_str%%"$_marker"*}"
}
quote_str() {
_str=$1 _qstr=
while [ "$_str" ]; do
_chr=${_str%"${_str#?}"}
if [ "$_chr" = "'" ]; then
_qstr=$_qstr"'\\''"
else
_qstr=$_qstr$_chr
fi
_str=${_str#?}
done
printf "'%s'" "$_qstr"
}
# [a-zA-Z_][a-zA-Z_0-9]
valid_vname() {
_vname=$1
case $_vname in
[[:lower:][:upper:]_]*)
;;
*)
return 1
;;
esac
_vname=${_vname#?}
while [ "$_vname" ]; do
case $_vname in
[[:lower:][:upper:]_[:digit:]]*)
;;
*)
return 1
;;
esac
_vname=${_vname#?}
done
return 0
}
ws='
'
input_file=$1
[ "$input_file" ] || {
printf '%s\n' 'usage: script <file>' >&2;
exit 1
}
while IFS== read -r _name _value; do
name=$(trim_left "$(trim_right "$_name" "$ws")" "$ws")
case $_value in
*'#'*)
value=$(trim_comment "$_value" '#')
;;
*'//'*)
value=$(trim_comment "$_value" '//')
;;
esac
value=$(trim_left "$(trim_right "$value" "$ws")" "$ws")
if valid_vname "$name"; then
eval "$name=$(quote_str "$value")";
fi
done < "$input_file";
echo "$srcdir"
echo "$prefix"
答案3
#!/bin/sh
FILENAME="<path>"
while read LINE
do
echo "$LINE"
if echo "$LINE" | grep -E -q "^srcdir*"
then
LINE=$(echo $LINE | cut -d"#" -f1) # No Comment, strip part after #
LINE=$(echo $LINE | awk -F" // " '{print $1;}') # No Comment, strip part after //
LINE=$(echo $LINE | tr -d ' ')
srcdir=$(echo $LINE | tr -d '^srcdir=')
break
fi
done < "$FILENAME"
echo $srcdir