Shell 实战大全
变量
shell中的变量,一般用 ${dir} 还是 $dir 会更好一些,两种有什么异同?
在 Bash shell 中,${dir}
和 $dir
都可以用来引用变量。它们的主要区别在于如何处理变量名后面紧跟着的字符。以下是它们的异同点:
-
使用大括号
{}
的情况:${dir}
:大括号{}
可以明确地标识变量名的边界,从而避免与后面紧跟的文本混淆。这在变量名后面跟着其他字符时特别有用,比如在字符串连接时或在数组元素访问时。- 例如,
${dir}ectory
可以确保在变量名dir
后面立即跟着ectory
,而不会被解释为一个名为dir
ectory 的变量。
-
不使用大括号
{}
的情况:$dir
:直接使用$
符号来引用变量,通常适用于简单的变量引用,没有后续字符或者后续字符已经被明确分隔的情况下。在这些情况下,不使用大括号也是允许的,比如在简单的赋值、条件判断或输出中。
综上所述,使用 ${dir}
可以提高代码的可读性和可维护性,特别是在变量名后面紧跟着其他字符时。但在某些简单的情况下,可以直接使用 $dir
,这更加简洁明了。选择使用哪种形式主要取决于代码的上下文和个人偏好。
遍历
你可以将这三个目录路径放入一个数组中,然后使用循环来遍历数组中的每个目录。以下是相应的 Shell 脚本示例:
#!/bin/bash
# 定义目录数组
directories=("/app/dat" "/app/ok" "/app/ddl")
# 循环遍历目录数组
for dir in "${directories[@]}"; do
echo "处理目录: $dir"
# 遍历当前目录下的文件
for file in "$dir"/*; do
if [ -f "$file" ]; then
echo "处理文件: $file"
# 在这里执行具体的业务处理操作
fi
done
done
在这个脚本中,我们首先定义了一个名为 directories
的数组,其中包含了三个目录的路径。然后,我们使用一个嵌套的 for
循环来遍历每个目录。在内部循环中,我们遍历当前目录下的文件,并执行特定的业务处理操作。
你可以在 # 在这里执行具体的业务处理操作
的注释下方编写你的业务处理逻辑。
函数
确实,上述的 parse_mapping()
方法在可读性上可能不是最佳选择。我们可以改进这个方法,使其更易读和易于理解。以下是一个优化后的版本:
#!/bin/bash
# 解析映射关系函数
parse_mapping() {
local table_name="$1"
local mapping_file="$2"
# 检查映射文件是否存在
if [ ! -f "$mapping_file" ]; then
echo "错误:映射文件 '$mapping_file' 不存在。"
return 1
fi
# 查找指定表名的映射关系
local mapping=$(grep "^$table_name=" "$mapping_file")
if [ -n "$mapping" ]; then
local partition_field="${mapping#*=}"
echo "表名: $table_name,分区字段: $partition_field"
else
echo "未找到与 '$table_name' 相关的映射关系。"
return 1
fi
}
# 调用解析映射关系函数
parse_mapping "T_78_TBL" "mapping.txt"
这个优化后的方法改进了可读性,并添加了一些错误处理的逻辑。以下是改进的主要点:
- 将表名和映射文件作为函数的参数,以提高函数的灵活性和重用性。
- 添加了对映射文件是否存在的检查,以避免尝试解析不存在的文件。
- 使用
grep
命令来查找指定表名的映射关系,并对结果进行判断处理。 - 使用
${variable#pattern}
语法从匹配的字符串中提取分区字段,避免了使用复杂的循环结构。
通过这些改进,函数变得更易读、更灵活,同时保留了与原始函数相同的功能。这样可以提高代码的可维护性和可读性。
在Shell脚本中,函数的返回值是通过标准输出传递的,可以通过命令替换或使用 $()
语法来接收函数的返回值。在这种情况下,parse_mapping()
函数可以通过输出所需的结果,然后在调用它的地方通过命令替换来接收返回值。
例如,如果我们想要在脚本中捕获 parse_mapping()
函数的输出,可以像这样调用它:
result=$(parse_mapping "T_78_TBL" "mapping.txt")
echo "$result"
这将执行 parse_mapping()
函数,并将输出保存到 result
变量中。然后,我们可以使用 echo
命令打印出 result
变量的值。
另外,如果函数需要传递多个返回值,则可以通过标准输出打印多个值,并使用适当的分隔符(如空格或换行符)来区分它们。在调用函数时,可以使用命令替换和 read
命令来分别读取这些返回值。
更改目录权限
根据你提供的信息,挂载目录/nas
的权限设置为drwxrwxrwx
,所有者和所属组都是app
。这意味着所有用户都具有读、写和执行该目录的权限。
为了确保数据库服务能够正常使用这个挂载目录,你可能需要进行以下操作:
-
更改目录所有者:
确保目录的所有者是数据库服务所使用的用户(通常是postgres)。你可以使用chown
命令更改目录的所有者。例如:sudo chown -R postgres:postgres /nas
-
设置适当的权限:
将目录的权限设置为只允许所有者读、写和执行,而其他用户没有任何权限。这可以通过以下命令实现:sudo chmod -R 700 /nas
执行以上操作后,/nas
目录将具有适当的所有者和权限设置,以确保数据库服务可以正常访问和操作其中的文件。请确保在更改权限之前备份重要的数据,并确保这些更改不会影响其他系统或服务的正常运行。
实战
文件下载
download_files.sh
#!/bin/bash
####################.############$########1
#步骤:
#step0:从远程服务器(阿里云服务器)下载文件
#sep1:将dat文件转为 ore 文件
#step2:将 ore 文件上传到HDFS
#step3:load data hdfs文件到Hive库调度:
#crontab 定时调度#/15 12-14 每天中午12-14点之间,每隔15分钟执行一次)
#crontab #/15 12-14syne_data.sh >> xxx.1og(按天分割)
#其他:
#windows开发在linux执行报错换行符问,可通过该命令转换:dos2unix syne_file_to_hive.sh
#file_name="ECLDB_t_c_i9_ecl_final_regult_h_20240320_F.dat"
#################################################################
#------下载远程文件BEGIN ----
#ANSI颜色定义
RED='\033[0;31m'
NC='\033[0m No Color'
DELIMITER="\u0001"#文本分隔符
etldate=$(date'+%Y%m%d')
#etldate="20240331"
echo " >>>>>>>>>>> 开始下载s{etldate)的文件<<<<<< "
start_time="$(date +%s)"
#远程服务器连接信息
IP=""
PORT=22
USER=""
PASSSTR=""
SECSTR="待获取"
PASSWORD=$(eoch"$SECSTR" | openss1 enc -d -aes-256-cbc -a -a1t-pbkde2 -paa= pass:$DASSSTR | tail -n1)
#远程FTP服务器目录
BASE_SRCDIR="/bdpdata/BYD-00-STAGE/ML/WHLXOADB/AML"
本地服务器基目录
BASE_DESDIR="/app/nfs_eyne/AML"
#本地服务器目录(需要同步det、ok、ddI)
#mkdir -p /app/nfs_=ync/AML/dat
#mkdir -p /app/nfs_sync/AML/ok
#mkdir -p /app/nfs_sync/AML/ddI
#chmod -R 755 /app/nfs_gync/AML/dat
#chmod -R 755 /app/nfs_syne/AML/ok
#chmod -R 755 /app/nfs_syne/AML/ddl
#业务目录
dat dir="dat"
ok_dir="ok"
ddl_dir="ddl"
#创建本地目录
dir_arr=("$dat_dir" "$ok_dir" "$ddl_dir")
for dir in "${dit arr[@]}";do
#拼接路径,如/app/nfs_sync/AML/dat/20240401
cur_desdir="${BASE_DESDIR}/${dir}/${etldate}"
cur_sredir="${BASE_SRCDIR}/${diz}/${etldate}"
#判断目录是否存在。如果不存在,则创建
if[!-d seur desdir ]; then
mkdir -p $cur_desdir
echo "> mkdir -p scur_desdir"
fi
done
# 全路径
cur_srcdir_ok="${BASE_SRCDIR}/${ok_dir}/${etldate}"
cur_srcdir_ddl="${BASE_SRCDIR}/${ddl_dir}/${etldate}"
cur_srcdir_dat="${BASE_SRCDIR}/${dat_dir}/${etldate}"
cur desdir_ok="${BASE_DESDIR}/${ok_dir}/${etldate}"
cur_desdir_ddl="${BASE_DESDIR}/*{ddl_d1z}/${etldate}"
cur_desdir_dat="s{BASE_DESDIR}/*{dat_dix}/${etidate}"
# 检查远程目录(ok)是否存在
lftp -e "cd scur_aredir_ok;exit" -u "$USER","$PASSWORD" $IP
#获取上一个命令的退出状态码,并判断目录是否存在,存在则下载ok文件,不存在则退出程序
STATUS=$?
if [ $STATUS -eq 0 ];then
lftp -u "${UEER},${PASSWORD}" sftp://"${iP}:${PORT}"<<EOF
set net:reconnect-interval-base 5
set net:max-retries 3
set net:timeout 10m
set xrer:clobber on
set sftp:connect-program "ssh -a-x-0 StrietHostKeyChecking=no"
et et
cd "$(cur_arcdir_ok)"
lcd "$(cur.deadir_ok)"
mirzor --ume-pget-n-s --continde overbose
bye
EOF
#遍历下载下来的ok文件
for ok file in "$cur_dendir_ok"/*;do
if [ -f "$ok_file" l;then
#提取文件名
# filename="ECLDB_t_e_i9_ecl_final_result_h_20240320_F.dat"
filename=$ (basename"$ok file")
#echo "filename=$filename"
# 解析ok、ddi文件名
dat_ filename="${filename/%.ok/.dat}"
ddl_filename="${filename/t.ok/.ddl}"
#echo "dat_filename=$dat_filename"
#echo "ddl_filename=$ddl_filename"
#判断远程服务器dat路径是否存在,存在则获取文件列表,并下载存在ok文件的相应的dat文件
lftp -e "cd scur_aredir_dat;exit "-u "sUSER","$PASSWORD" $IP
dat_file_status=$?
if [ "$dat_file_status" -eq 0 ];then
echo"开始下载$dat_filename"
lftp -u "${USER},${PASSWORD}" sftp://"${IP}:${PORT}"<<EOF
set net:reconnect-interval-base5
set net:max-retries 3
set net:timeout 10m
set xfer:clobber on
set sttp:connect-progrem "ssh -a -x -o StrietHostKeyChecking=no"
cd "${cur gredir dat}"
pget -n 5 "$dat_filename" -o "$cur_desdir _dat"
bye
EOF
download_dat_flag=$?
#获取下载结果状态并判断下载结果,下载完成则输出结果,下载失败输出结果并退出程序
if [ "$download_dat_flag" -eq 0 ];then
echa ">>>>$dat_Eilenane download complete"
e1se
echo ">>>>sdat_filenamedowmload tailed,exit"
exit 1
fi
else
echo"$(sur_aredir_dat): no such file,exit"
exit 1
fi
#判断远程服务器da1路径是否存在,存在则下载ox文件的相应的ddl文件,不存在则退出
lftp -e "cd $cur_srcdir_ddl;exit " -u "$USER","$PASSWORD" $IP
ddl_file_status=$?
if [ "$ddl file statua" -eq 0 ];then
echo"开始下载$didl_filename"
lftp -u "${USER},${PASSWORD}" sftp://"${IP}:${PORT}" <<EOF
set net:reconnect-interval-base 5
set net:max-retries 3
set net:timeout 10m
set xfer:clobber on
set sftp:connect-program "ssh -a -x -o StrictHostKeyChecking=no"
cd "${cur $redir ddl}"
pget -n 5 "$ddl_filename” -o "$scur dendir_ddl"
bye
EOF
#获取下载结果状态并判断下载结果,下载完成则输出结果,下载失败输出结果并出程序
download_ ddl_flag=$?
if [ "$download_ddl_flag" -eq 0 ];then
echo ">>>>$ddl_filename download complete"
else
echo ">>>>$ddl_filename download failed,exit"
exit 1
fi
else
echo "&(eur_aredir_ddl):no such file,exit"
exit
fi
fi
done
end time=$ (date +%s)
cost_time=$(end_time - start_time))
echo " >>>>>>>>>>> Daimload +$(etldate) files complated, cnes time $coat_time s <<<<<"
# 下截远程文件 END
exit 1
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)