我一直面临着制造无数简单" shell脚本通用于某些不那么通用的进程。我被迫使用配置文件,或者更确切地说基于(在某些情况下)已经实现的内容:在运行时包含脚本中的配置文件或使用source命令。
我尽力偏离基于众多disagreements的人,但我可能别无选择。我需要能够允许诸如外卡,自定义数组和将当前变量放在下一个变量中。我的问题主要是答案最简单。
1。我可以让我当前的函数用于解释配置文件中的$ vars吗?
2。这有关系吗?是否比仅使用源更安全?
我的配置文件看起来像一个INI文件,虽然我不是那样打算因为我不在乎。
[production]
file_date="%Y%m%d" #WAAAA That's not how we format our dates :(
#file_date="gotcha rm testfile"
ssh_user=myuser
server=myserver.net
source_directory=/home/myuser/inb
destination_directory="ONE"
destination_directory="TWO"
destination_directory="THREE"
file_name="SOME_UNIQUE_CONSTANT_*_$file_date" #Or no date
zip_file="SLIGHTLY_DIFFERENT_$file_name.zip" #Or no zip
data_file="A_LITTLE_DIFFERENT_$file_name.dat" #Or no extension
#What to use (sftp|sftpg3|...)
#Everything in directory yes/no
#Everything named *_THIS_*
#Rename *_THIS_* to *_THAT_*
#Who the hell knows...
[testing]
file_date="%Y%m%d" #WAAAA That's not how we format our dates :(
ssh_user=jsharpe
server=myserver.net
file_name="TEST_FILE_$file_date"
zip_file="$file_name.zip"
data_file="$file_name.dat"
source_directory="/home/$ssh_user/$server/$file_name"
destination_directory="test1"
destination_directory="test2"
destination_directory="test3"
[log]
level=verbose
report_on_warning=false
report_on_error=true
report_email_list="myemail@myserver.net"
report_email_list="youremail@myserver.net"
这是我阅读变量的主要功能,它可以很好地防止哑输入。我尝试先使用declare然后使用相同结果的case。一切都是字面上的解释,这实际上是我想要的,试图保护我的脚本免受它读取的配置文件,但它是苦乐参半。还要感谢antonio他的帖子让我在右边?方向。
更新2:修改了使用函数的情况并声明而不是eval并在配置行中搜索任何以前包含的变量。 使搜索函数递归为n个变量(如图所示) 用于测试的源目录)。声明有一个数组选项 我的配置只重复相同的变量。现在我只需要 从配置文件中测试通配符。请尝试这个和或让我知道 如果你能用我的方法想出任何重大问题或缺陷。我知道大多数情况都没有函数调用,如果有一个尚未定义的变量的引用,我需要出现一些明显的错误。
function var_in_var() {
var_in_var_match = "$1"
if [[ "$1" =~ "$" ]] ; then
for var in "${prev_case[@]}" ; do :
if [[ "$1" =~ "$var" ]] ; then
local var_val="${!var}"
var_in_var_match="${1//\$$var/$var_val}"
var_in_var "$var_in_var_match" || return
return 0
fi
done
fi
}
function read_config_file() {
#Problematic if user is not knowlegeable on how to correctly make / modify config files.
echo "Reading config file $config_file"
shopt -s extglob # Turn on extended globbing.
#temp_file=$"$file_basename_$RANDOM.tmp"
tr -d '\r' '\t' < "$config_file" > "$temp_file" #Remove DOS EOL characters and tabs
local line_num=1 #Counter in case we need to error out config line number
local section=""
while IFS='= ' read lhs rhs ; do :
if [[ "$lhs" =~ "["*"]" ]] ; then
lhs="${lhs%\]}" #Remove closing brackets
lhs="${lhs#\[}" #Remove opening brackets
section="$lhs"_
elif [[ ! $lhs =~ ^\ *# && -n $lhs ]] ; then
rhs="${rhs%%\#*}" # Del in line right comments (like this one)
rhs="${rhs%%*( )}" # Del trailing spaces
rhs="${rhs%\"*}" # Del closing string quotes
rhs="${rhs#*\"}" # Del opening string quotes
#declare -x "$section"_"$lhs"="$rhs" #Does not store $vars from config file
x="$section$lhs"
rhs="${rhs//$/\$$section}"
case $lhs in
"ssh_user" ) declare "$x=$rhs" ; prev_case+=("$x");;
"server" ) declare "$x=$rhs" ; prev_case+=("$x");;
"source_directory" ) var_in_var $rhs || return ; declare "$x"="${var_in_var_match:-$rhs}" ; prev_case+=("$x");;
"file_date" ) declare "$x=$(date +"$rhs")" ; prev_case+=("$x");;
"file_name" ) var_in_var $rhs || return ; declare "$x"="${var_in_var_match:-$rhs}" ; prev_case+=("$x");;
"zip_file" ) var_in_var $rhs || return ; declare "$x"="${var_in_var_match:-$rhs}" ; prev_case+=("$x");;
"data_file" ) var_in_var $rhs || return ; declare "$x"="${var_in_var_match:-$rhs}" ; prev_case+=("$x");;
"destination_directory" ) declare -a "$x+=($rhs)" ; prev_case+=("$x");;
"level" ) declare "$x"="$rhs" ; prev_case+=("$x");;
"report_on_warning" ) declare "$x"="$rhs" ; prev_case+=("$x");;
"report_on_error" ) declare "$x"="$rhs" ; prev_case+=("$x");;
"report_email_list" ) declare "$x"="$rhs" ; prev_case+=("$x");;
* ) echo "Unknown variable $lhs skipping..." ; exit 1 ;;
esac
elif [[ $lhs == "" ]] ; then
if ! [[ $rhs == "" ]] ; then
echo "Reading line $line_num from file failed. Variable name is null. Exiting read..." ; has_warnings=true ;
return 1
fi
elif [[ $rhs == "" ]] ; then
echo "Reading line $line_num from file failed. Variable value is null. Exiting read..." ; has_warnings=true ;
return 1
else
if [[ $lhs =~ ^\ *# ]] ; then
echo "Line $line_num is a comment, skipping..."
else
echo "Reading line $line_num from file failed. Exiting read..." ; has_warnings=true ;
return 1
fi
fi
line_num=$(($line_num + 1))
done < "$temp_file"
#source "somefile.config" <-- Bad idea
shopt -u extglob # Turn off extended globbing.
echo_out_production_variables
echo_out_testing_variables
return 0
}
function echo_out_testing_variables() {
echo "Testing SSH_User: $testing_ssh_user"
echo "Testing Server: $testing_server"
echo "Testing Source Directory: $testing_source_directory"
echo "Testing File Date: $testing_file_date"
echo "Testing File Name: $testing_file_name"
echo "Testing Zip File: $testing_zip_file"
echo "Testing Data File: $testing_data_file"
for destination in "${testing_destination_directory[@]}" ; do : ; echo "Testing Destination(s): $destination" ; done
}
function echo_out_production_variables() {
echo "Production SSH_User: $production_ssh_user"
echo "Production Server: $production_server"
echo "Production Source Directory: $production_source_directory"
echo "Production File Date: $production_file_date"
echo "Production File Name: $production_file_name"
echo "Production Zip File: $production_zip_file"
echo "Production Data File: $production_data_file"
for destination in "${production_destination_directory[@]}" ; do : ; echo "Production Destination(s): $destination" ; done
}
我的脚本输出。
-bash-3.2$ ./get_file.bash -f test.conf
Reading config file test.conf
Line 3 is a comment, skipping...
Line 13 is a comment, skipping...
Line 14 is a comment, skipping...
Line 15 is a comment, skipping...
Line 16 is a comment, skipping...
Line 17 is a comment, skipping...
Production SSH_User: myuser
Production Server: myserver.net
Production Source Directory: /home/myuser/inb
Production File Date: 20151211
Production File Name: SOME_UNIQUE_CONSTANT_*_20151211
Production Zip File: SLIGHTLY_DIFFERENT_SOME_UNIQUE_CONSTANT_*_20151211.zip
Production Data File: A_LITTLE_DIFFERENT_SOME_UNIQUE_CONSTANT_*_20151211.dat
Production Destination(s): ONE
Production Destination(s): TWO
Production Destination(s): THREE
Testing SSH_User: jsharpe
Testing Server: myserver.net
Testing Source Directory: /home/jsharpe/myserver.net/TEST_FILE_20151211
Testing File Date: 20151211
Testing File Name: TEST_FILE_20151211
Testing Zip File: TEST_FILE_20151211.zip
Testing Data File: TEST_FILE_20151211.dat
Testing Destination(s): test1
Testing Destination(s): test2
Testing Destination(s): test3
更新1:我查看了eval并不比source更好但是它让我保持当前的功能设置。我的案例陈述 看起来像
"file_date" ) eval "$x"=$(date +"${rhs}") ;; "ssh_user" ) eval "$x"="${rhs}" ;; "data_file" ) eval "$x"="${rhs}" ;;
但是我通过将此行添加到我的配置文件中来打破它:
data_file="gotcha rm testfile"
我认为这更接近我想要的,因为我有适度的控制权 这一点超过了字符串,可能之前可以消毒它 试图评估它。这是一种可能性。
[SPOILER]:我的简单474行脚本的作用......
(sftp | scp | connect direct | sftpg3 | ...)n个文件从一个位置到n个位置。当没有人能够就他们的文件命名达成一致意见时,乐趣就开始了,如果需要在发送之前重命名,如果所有文件或仅发送一些文件,如果需要添加日期,如果它是压缩的,并且需要在目的地解压缩。