【问题标题】:why 'ls' command printing the directory content multiple times为什么'ls'命令多次打印目录内容
【发布时间】:2020-12-25 15:47:06
【问题描述】:

我有以下 shell 脚本,我想在其中检查远程机器上的特定目录内容并将它们打印到文件中。

file=serverList.csv
n=0
while [ $n -le 2 ]
do
while IFS=: read -r f1 f2
do
      # echo line is stored in $line
       if echo $f1 | grep -q "xx.xx.xxx";
       then
           ssh user@$f1 ls path/*war_*  > path/$f1.txt < /dev/null; ls path/*zip_* >> path/$f1.txt < /dev/null; 
           ssh user@$f1 ls -d /apps/jetty*_* >> path/$f1.txt < /dev/null; 
       fi
done < "$file"
sleep 15
n=$(( n+1 ))
done

我每 2 分钟在 cron 作业中使用此脚本,如下所示:

*/2 * * * * /path/myscript.sh 

但不知何故,我最终得到了以下输出文件:

/apps/jetty/webapps_wars/test_new.war
path/ReleaseTest.static.zip_2020-08-05
path/ReleaseTest.static.zip_2020-08-05
path/ReleaseTest.static.zip_2020-08-05
path/jetty_xx.xx_2020-08-05
path/jetty_new
path/jetty_xx.xx_2020-08-05
path/jetty_new

我不确定为什么我会两次获得列表中的文件,有时是 3 次。但我直接从腻子执行shell,它工作正常。为了更正此脚本,我需要进行哪些更改?

【问题讨论】:

  • 您使用了太多的* 通配符和许多ls 而不是更好的过滤器,因此您会得到许多相似的行:然后两个解决方案 piggy one 过滤器输出;好的一篇评论你循环使用更多的正则表达式和更好的文件名过滤;您可能会考虑使用 find (with -o... -o .... -o ...) 来获取您的文件名列表,您还将获得唯一且没有ls的结果编写脚本的一种不好的做法例如,在您的情况下,您会看到它为什么不好

标签: bash shell cron


【解决方案1】:

例子:

~$ cd tmp
~/tmp$ mkdir test
~/tmp$ cd !$
cd test
~/tmp/test$ mkdir -p apps/jetty/webapp_wars/ && touch apps/jetty/webapp_wars/test_new.war
~/tmp/test$ mkdir path
~/tmp/test$ touch path/{ReleaseTest.static.zip_2020-08-05,jetty_xx.xx_2020-08-05,jetty_new}
~/tmp/test$ cd ..
~/tmp$ listpath=$(find test/path \( -name "*2020-08-05" -o -name "*new" \) )
~/tmp$ listapps=$(find test/apps/  -name "*war" )
~/tmp$ echo ${listpath[@]}" "${listapps[@]} | tr " "  "\n" | sort  > resultfile 
~/tmp$ 
~/tmp$ cat resultfile 
test/apps/jetty/webapp_wars/test_new.war
test/path/jetty_new
test/path/jetty_xx.xx_2020-08-05
test/path/ReleaseTest.static.zip_2020-08-05
~/tmp$ rm -rf test/ && unset listapps && unset listpath && rm resultfile 
~/tmp$

这样,您在if...then...else 代码块中查找的每个模式只会得到一个结果。

只需调整ssh ..... find 命令并处理引号和括号,但有最简单的解决方案,这样您就不必从头开始重写脚本。如果您使用它们,请注意本地/远程变量。

【讨论】:

  • 没有-maxdepth 的普通find 也将遍历子目录,OP 的原始代码没有这样做。目前尚不清楚这是否可以接受。
【解决方案2】:

你真的是should not use ls,但根本问题可能是三个单独的命令和三个单独的通配符可以匹配同一个文件三次。

此外,您的一个命令是在本地执行的(您忘记将ssh 等放在第二个之前),因此如果通配符在您的本地计算机上匹配,则会产生不反映远程服务器上的情况。

试试这个重构。

file=serverList.csv
n=0
while [ $n -le 2 ]
do
    while IFS=: read -r f1 f2
    do
        # echo line is stored in $line  <- XXX this is not true
        if echo "$f1" | grep -q "xx.xx.xxx";
        then
            ssh user@$f1 "printf '%s\n' path/*war_* path/*zip_* /apps/jetty*_*" | sort -u >path/"$f1".txt < /dev/null
        fi
    done < "$file"
    sleep 15
    n=$(( n+1 ))
done

sort 消除了所有重复项。这假设您的文件名都不包含换行符;如果是这样,您需要使用能够可靠处理它们的东西(尝试 printf '%s\0'sort -z,但它们不可移植)。

ls 肯定也会接受三个不同的通配符,但就像上面的链接解释的那样,你真的不想在脚本中使用 ls

【讨论】:

  • 如果这解决了您的问题,请考虑投票和/或接受它。您也可以发布自己的答案并接受。接受答案会将您的问题标记为已解决,并以 15 点声望奖励回答者。另见help.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多