有没有人通过bash脚本更智能地准备模板文件?
这是当前的脚本:
#!/bin/bash
projectDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
echo "Project root: $projectDir"
echo "> Is this the project root directory? (y/n)"
read validProjectPath
#if [ "$isProjectDir" != "y" ] then exit 1 fi
echo "> Your OS user name (e.g. peter):"
read userName
echo "> VM IPv4 address (e.g. 192.168.178.2):"
read ipv4
# setup
echo "prepare configuration files..."
for f in $(find "$projectDir/vagrant" -name "*.template" -type f); do
toFile=${f/.template/}
cp $f $f.bak
sed "s/_CHANGE_PRODIR_/$projectDir/g" $f.bak > $f.bak1
sed "s/_CHANGE_USERNAME_/$userName/g" $f.bak1 > $f.bak2
sed "s/_CHANGE_IPV4_/$ipv4/g" $f.bak2 > $toFile
rm -f $f.bak
rm -f $f.bak1
rm -f $f.bak2
done
echo "... done!"
感谢您的回复。 吉姆
答案 0 :(得分:3)
这整个临时文件业务完全没必要。
for f in $(find "$projectDir/vagrant" -name "*.template" -type f); do
sed -e "s%_CHANGE_PRODIR_%$projectDir%g" \
-e "s%_CHANGE_USERNAME_%$userName%g" \
-e "s%_CHANGE_IPV4_%$ipv4%g" "$f"> "${f/.template/}"
done
如果您的sed
方言不喜欢多个-e
选项,请尝试将整个脚本放在双引号之间,并在命令之间添加换行符或分号。
sed "s%_CHANGE_PRODIR_%$projectDir%g
s%_CHANGE_USERNAME_%$userName%g
s%_CHANGE_IPV4_%$ipv4%g" "$f"> "${f/.template/}"
(是的,这是一个长的双引号字符串,跨越三条物理线。)
更新:我还将分隔符更改为%
,以便替换值可以安全地包含斜杠。如果你也想允许百分号,你显然还要提出另一个分隔符(冒号,感叹号,分号都很受欢迎)。
答案 1 :(得分:2)
好吧,我建议您使用sed
运行-i
命令,并使用""
包围输出文件,以便它支持路径中包含空格的文件并将其组合进入一个sed
调用。就像这样,
cp "$f" "$toFile"
sed -i -e "s/_CHANGE_PRODIR_/$projectDir/g" \
-e "s/_CHANGE_USERNAME_/$userName/g" \
-e "s/_CHANGE_IPV4_/$ipv4/g" "$toFile"
# rm -f $f.bak
# rm -f $f.bak1
# rm -f $f.bak2
此外,
echo "> Your OS user name (e.g. peter):"
read userName
可能
userName=$(whoami)
取决于您使用它的目的。
答案 2 :(得分:0)
除了其他建议之外,以更可靠的方式测试/验证输入的一种方法是将字符串数据转换为小写,然后将测试限制为您需要的子字符串:
echo "> Is this the project root directory? (y/n)"
read validProjectPath
ans="${validProjectPath,,}" # conversion to lower-case
[ "${ans:0:1}" != "y" ] && exit 1 # test using compound-command
您可以使用sed“编辑就地”.bakX
来删除-i
文件:
# setup
echo "prepare configuration files..."
for f in $(find "$projectDir/vagrant" -name "*.template" -type f); do
toFile=${f/.template/}
cp "$f" "$toFile"
sed -i "s/_CHANGE_PRODIR_/$projectDir/g" "$toFile"
sed -i "s/_CHANGE_USERNAME_/$userName/g" "$toFile"
sed -i "s/_CHANGE_IPV4_/$ipv4/g" "$toFile"
done
唯一的另一个想法(不是推荐)是使用readlink -f ${0}
来返回调用脚本名称,然后使用dirname
或简单子字符串提取${fullname%/*}
来解析路径。您使用BASH_SOURCE
似乎可以正常工作。
答案 3 :(得分:0)
您可以使用awk
与gsub
进行全局替换文件,而不是创建不必要的临时文件。
for f in $(find "$projectDir/vagrant" -name "*.template" -type f); do
toFile=${f%.template}
awk -v p="$projectDir" -v u="$userName" -v ip=$ipv4 '{
gsub("_CHANGE_PRODIR_", p)
gsub("_CHANGE_USERNAME_", u)
gsub("_CHANGE_IPV4_", ip)
}' "$f" > "$toFile"
done
最好不要依赖记住了VM IP地址的用户。可以使用awk
:
ips=($(awk '{
m=match($0,/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/,a)
if(m && a[0] !~ /^127./)
print a[0]
}' < <(ifconfig)
))
然后,select
循环可供用户从列表中选择IP。
echo "Select the VM IPv4 address:"
select opt in ${ips[@]}; do
case $opt in
${ips[0]})
ipv4=$opt
break
;;
${ips[1]})
ipv4=$opt
break
;;
${ips[2]})
ipv4=$opt
break
;;
*)
echo invalid option
;;
esac
done