SUSE Linux 15下Shell脚本无法正确收集符合条件的文件名至变量的问题求助
SUSE Linux 15下Shell脚本无法正确收集符合条件的文件名至变量的问题求助
嘿,我一眼就看出你遇到的是Shell脚本里非常典型的子shell变量作用域问题!先给你解释清楚原因,再给你几个靠谱的解决方案。
问题根源
你用了find ... | while read ...这种管道写法,在Bash里,管道两端的命令都会在独立的子shell中运行。也就是说,你的while循环是在子shell里执行的,循环中对DESTINATIONS变量的所有修改,都只会作用于子shell里的变量副本,不会传递回父shell。所以当循环结束后,父shell里的DESTINATIONS变量其实根本没被正确更新,这就是为什么你只能看到一个文件名的原因。
另外还有个小细节:你要筛选的是“过去24小时内修改的文件”,但你的find用了-mtime -30(这是找30天内修改的文件),应该改成-mtime -1才符合你的需求哦。
解决方案1:用重定向替代管道(避免子shell)
把管道换成进程替换的重定向写法,这样while循环就会在父shell里执行,变量修改就能生效了:
DESTINATIONS="main_crontab" # 用< <(...)替代管道,让while在父shell运行 while read -d $'\0' file do DESTINATIONS+=" ${file}" done < <(find . -name "sample_file_*" -type f -mtime -1 -print0) echo ${DESTINATIONS}
解决方案2:用数组存储文件名(更安全,适配带空格的文件名)
如果你的文件名可能包含空格或特殊字符,用字符串拼接变量很容易出问题,推荐用数组来存储:
# 初始化数组,包含初始值"main_crontab" DESTINATIONS=("main_crontab") while read -d $'\0' file do DESTINATIONS+=("$file") done < <(find . -name "sample_file_*" -type f -mtime -1 -print0) # 打印数组所有元素,注意用[@]和双引号 echo "${DESTINATIONS[@]}"
解决方案3:直接将find结果赋值给数组(简化写法)
如果确定文件名没有空格,也可以直接把find的结果赋值给数组,写法更简洁:
DESTINATIONS=("main_crontab" $(find . -name "sample_file_*" -type f -mtime -1)) echo "${DESTINATIONS[@]}"
按照上面的方法修改后,就能正确收集到所有符合条件的文件名啦!
备注:内容来源于stack exchange,提问作者Sanjay Surve
相关产品推荐
相关产品推荐

