bash:设置脚本的更智能方式

时间:2014-09-01 05:39:41

标签: bash shell sh

有没有人通过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!"

感谢您的回复。 吉姆

4 个答案:

答案 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)

您可以使用awkgsub进行全局替换文件,而不是创建不必要的临时文件。

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

创建一组可能的IP地址
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