根据文件类型在目录中逐行融合文件

根据文件类型在目录中逐行融合文件

我有一个函数,save它被for循环中的其他函数调用,该函数是融合特定目录中相同类型的文件(根据每个文件的内容逐行复制到一个新文件)到他们的类型)。

融合文件的名称采用${x}_type_${y}.log以下格式:xy是来自调用函数 save 的其他函数的变量,类型是文件的类型。

我尝试使用cat,echopaste来融合文件,但它们都不起作用。当我运行脚本时,融合的文件根据融合的文件类型携带代码中设置的名称,但融合的文件为空,或者包含应该融合的文件的名称而不是其内容。

for file in *;
do
type=$( echo "$file" | awk -F'[.-]' '{print $2}' )
save () {
 if [[ "$type" == "$type1" ]];
  then
   cat "$file" >> "${x}_First_${y}.log"
 elif [[ "$type" == "$type2" ]];
  then
   cat "$file" >> "${x}_Second_${y}.log"
 elif [[ "$type" == "$type3" ]];
  then
   cat "$file" >> "${x}_Third_${y}.log"
elif [[ "$type" == "$type4" ]];
  then
   cat "$file" >> "${x}_Fourth_${y}.log"
 else
  echo "Nothing to do"
 fi
 }
done

我也尝试过将每个文件的内容逐行复制到新文件中,但它仍然不起作用。

for file in *;
do
type=$( echo "$file" | awk -F'[.-]' '{print $2}' )
save () {
  if [[ "$type" == "$type1" ]];
  then
      while IFS= read -r line
do
echo "$line"
echo -e "$line\n" >>"${x}_Request_${y}.log"

done <"$file"
  elif [[ "$type" == "$type2" ]];
  then
      while IFS= read -r line
do
echo "$line"
echo -e "$line\n" >>"${x}_Error_${y}.log"

done <"$file"
 elif [[ "$type" == "$type3" ]];
     then
      while IFS= read -r line
do
echo "$line"
echo -e "$line\n" >>"${x}_Critical_${y}.log"

done <"$file"
 elif [[ "$type" == "$type4" ]];
  then
 while IFS= read -r line
do
echo "$line"
echo -e "$line\n" >>"${x}_Test_${y}.log"

done <"filename"
 else
  echo "Nothing to do"
 fi
}
done

这是整个脚本

#!/bin/bash

env1="dev"
env2="prod"
type1="request"
type2="error"
type3="critical"
type4="test"

save () {
 if [[ "$type" == "$type1" ]];
  then
   cat "$file" >> "${m}_Request_${w}.log"
 elif [[ "$type" == "$type2" ]];
  then
   cat "$file" >> "${m}_Error_${w}.log"
 elif [[ "$type" == "$type3" ]];
  then
   cat "$file" >> "${m}_Critical_${w}.log"
elif [[ "$type" == "$type4" ]];
  then
   cat "$file" >> "${m}_Test_${w}.log"
 else
  echo "Nothing to do"
 fi
 }

week_range () {
 if [[ "$day" -ge 1 && "$day" -le 7 ]];
   then
    w="Wk1"
    save
 elif [[ "$day" -ge 8 && "$day" -le 14 ]];
  then
    w="Wk2"
    save
 elif [[ "$day" -ge 15 && "$day" -le 21 ]];
  then
    w="Wk3"
save
 elif [[ "$day" -ge 22 && "$day" -le 28 ]];
  then
    w="Wk4"
    save
 elif [[ "$day" -ge 29 && "$day" -le 31 ]];
  then
    w="Wk5"
    save
 else
echo "Nothing to do"
fi
 }

month_range () {
 if [[ "$month" -eq 1 ]];
 then
   m="Jan"
   week_range
elif [[ "$month" -eq 2 ]];
then
   m="Feb"
   week_range
elif [[ "$month" -eq 3 ]];
 then
   m="Mar"
   week_range
elif [[ "$month" -eq 4 ]];
 then
   m="Apr"
week_range
elif [[ "$month" -eq 5 ]];
 then
   m="May"
   week_range
elif [[ "$month" -eq 6 ]];
 then
   m="Jun"
   week_range
elif [[ "$month" -eq 7 ]];
then
   m="Jul"
   week_range
elif [[ "$month" -eq 8 ]];
then
   m="Aug"
   week_range
elif [[ "$month" -eq 9 ]];
 then
   m="Sep"
week_range
elif [[ "$month" -eq 10 ]];
 then
  m="Oct"
  week_range
elif [[ "$month" -eq 11 ]];
 then
  m="Nov"
  week_range
elif [[ "$month" -eq 12 ]];
then
  m="Dec"
  week_range
else
   echo "Nothing to do"
fi
 }
for file in *.log;
do
env=$( echo "$file" | awk -F'[.-]' '{print $1}' )
type=$( echo "$file" | awk -F'[.-]' '{print $2}' )
month=$((10#$( echo "$file" | awk -F'[.-]' '{print $4}' )))
day=$((10#$( echo "$file" | awk -F'[.-]' '{print $5}' )))

if [[ "$env" == "$env1" ]];
then
    cd Env1 && { month_range; cd -; }
elif [[ "$env" == "$env2" ]];
  then
    cd Env2 && { month_range; cd -; }
else
  echo "Nothing to do"
fi
done

这就是我的文件的样子

dev.critical-2021-01-05.log  prod.critical-2021-12-07.log
dev.critical-2021-08-09.log  prod.error-2021-02-21.log
dev.error-2021-08-01.log     prod.error-2021-07-29.log
dev.error-2021-08-07.log     prod.error-2021-10-22.log
dev.request-2021-08-01.log   prod.request-2021-01-02.log
dev.request-2021-08-12.log   prod.request-2021-04-10.log
dev.test-2021-09-03.log

这就是我期望在不同目录中的 dev 和 prod 所拥有的

Jan_Critical_Wk1.log         
Jan_Request_Wk1.log          
Jun_Request_Wk1.log  
Mar_Critical_Wk2.log        
May_Error_Wk2.log  
Feb_Error_Wk3.log      
Apr_Request_Wk2.log          
Aug_Critical_Wk1.log         
Aug_Critical_Wk2.log         
Aug_Error_Wk1.log            
Aug_Error_Wk2.log            
Aug_Request_Wk1.log          
Aug_Request_Wk2.log          
Nov_Error_Wk3.log
Oct_Error_Wk4.log
Sep_Request_Wk4.log
Jul_Error_Wk5.log            
Sep_Test_Wk1.log

答案1

您的错误是在移动到该文件不可用的另一个目录后尝试引用所cat引用的文件。$file

您似乎检查了文件名并据此对它们进行分类。

代码可以变得更简单。

#!/bin/bash

shopt -s nullglob

declare -A envdir

months=( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec )
envdir=( [dev]=Env1 [prod]=Env2 )

for name in *.log; do
        IFS='.-' read -r env type year month day suffix <<<"$name"

        m=${months[(10#$month) - 1]}
        w="Wk$(( 1 + (10#$day)/7 ))"

        if [ -z "$m" ] || [ ! -d "${envdir[$env]}" ]; then
                echo 'Nothing to do'
                continue
        fi

        cat -- "$name" >>"${envdir[$env]}/${m}_${type^}_$w.log"
done

上面使用的事实是类型的目录名称已经是文件名的一部分。我们只需要大写初始字符,我们用 来实现${type^}。文件名的不同部分使用 读入变量read

我们根据月份编号从数组中选择月份名称,而不是遍历一长串if, then,else列表。周数是根据天计算的。要使用的环境目录存储在关联数组 中envdir

我们不需要cd去任何地方。

nullglob如果不匹配任何内容,shell 选项会使通配模式完全消失。如果没有nullglob,模式*.log将被分配给name并且至少会发生一次循环迭代。

您还可以对选择文件名的方式进行更多限制,以确保只选择有效的文件。

#!/bin/bash

shopt -s nullglob extglob

declare -A envdir

months=( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec )
envdir=( [dev]=Env1 [prod]=Env2 )

for name in @(dev|prod).@(critical|error)-????-??-??.log; do
        # as before
done

请注意添加了extglobshell 选项。它允许我们编写ksh类似扩展的通配模式来匹配我们想要查看的特定名称。特别是,它允许我们用来@(pattern|pattern|pattern)匹配所包含的模式或字符串之一。

相关内容