【问题标题】:List files that are in directory1 but NOT in directory2 and vice versa?列出目录 1 中但不在目录 2 中的文件,反之亦然?
【发布时间】:2011-07-13 20:09:27
【问题描述】:

嘿,我开始编写 bash shell 脚本,我正在尝试为一个分配创建一个脚本,当您输入两个目录时,它将检查它们是否存在并根据错误消息显示,如果两个目录都存在,它将列出当前目录之间的差异。

$ cd dir-1
$ myshellscript . dir-2 (comparing . aka dir-1 against dir-2) 

输出:

Files that are in . but not in dir-2
-rw------- 1 ddddd users   1 2011-03-1 01:26 123123123

Files that are in dir-2 but not in .
-rw------- 1 ddddd users   1 2011-03-1 01:26 zzzzzzzzzzzz

到目前为止,我似乎没有检测到目录是否存在或列出差异:

dir-1=$1
dir-2=$2

if [ $# > 2  ]
   then
      echo "Usage: compdir dir-name1 dir-name 2"
      exit 1
   elif [ $# < 2 ]
      then
         echo "Usage: comdir dir-name1 dir-name 2"
   elif [ ! -d "$@" ]
      then
         echo "/$@ is not a valid existing directory"
   else
      exit 0
fi

echo $dir-1
echo $dir-2

我必须使用的命令列表,否则我会使用 comm -32 &lt;(ls -la dir-1) &lt;(ls -la dir-2)

http://dl.dropbox.com/u/20930447/index.html

【问题讨论】:

  • 是的,有很多更好的解决方案,但是哦,好吧 =\

标签: linux bash shell


【解决方案1】:

我喜欢用 diff 来比较:

diff <(ls -1 dir1) <(ls -1 dir2) | awk '{if ($1==">") print "in dir 2: "$2; if($1=="<") print "in dir 1: "$2;}'

你也可以用 read 来分析它:

diff <(ls -1 $dir1) <(ls -1 $dir2) | while read status filename
do
  [ "$status" == "<" ] && echo "in dir 1: $(ls -l $dir1/$filename)"
  [ "$status" == ">" ] && echo "in dir 2: $(ls -l $dir2/$filename)"
done

【讨论】:

  • 这似乎行得通,虽然我不知道如何把它变成 ls -la 格式。
【解决方案2】:

您想要做的事情的基本方法,已经使用类 unix 系统上可用的diff 实用程序或在 Windows 上使用 cygwin 或 GnuWin 完成。你应该利用这个事实。

如果我的目录ab 包含以下内容:

ezra@ubuntu:~$ ls -R
.:
a  b

./a:
d  e  f  x  y  z

./b:
i  j  k  x  y  z

每个目录中的xyz 完全相同。

我可以像这样使用diff 命令实现你想要的:

ezra@ubuntu:~$ diff a b
Only in a: d
Only in a: e
Only in a: f
Only in b: i
Only in b: j
Only in b: k

如果我向每个不同的目录(名为 new)添加一个新文件,我会得到以下信息:

ezra@ubuntu:~$ diff a b
Only in a: d
Only in a: e
Only in a: f
Only in b: i
Only in b: j
Only in b: k
diff a/new b/new
1c1
< ezraa
---
> ezra

也就是说,它甚至会告诉您文件中出现差异的方式和位置。当然,如果您不想要或不需要此功能,您可以不使用它。

您还可以获得以下信息:

ezra@ubuntu:~$ diff a c
diff: c: No such file or directory

随着这个程序的繁重工作由 diff 完成,您编写的大部分内容将解析该命令的输出,然后根据您的需要对其进行操作或输出。

当您执行此操作时,awksed 之一可能会特别感兴趣。

【讨论】:

  • 是的,我知道了,但是在 OP 中,输出没有按照您的回答列出,因此您的回答不适用,抱歉!
  • 我不打算为你写你的程序。对不起!
  • 对不起,我处于“混蛋模式”,对这个程序感到非常沮丧,谢谢你的帮助;)
【解决方案3】:

这几乎可行。它主要是在两个目录之间按字母顺序排列相似位置的文件时失败。

sdiff -s <(ls -1 dir1) <(ls -1 dir2)

【讨论】:

  • 这很好用,除了我不能在输出之间有消息之外。我需要回显一条消息,然后在 a 中显示与 b 不同的文件,然后输出另一条消息并在 a 中输出不同的文件。
【解决方案4】:

有点粗略 - 但我一直使用的最简单的方法是(可以使用 diff 参数,我通常使用不同的 grep

diff -rcw DIR1 DIR2| grep ^Only

然后你可以随意排序和格式化

修改为格式(效率较低,因为我们在这里运行 diff 两次...很容易解决)

echo files only in $dir1
LST=$(diff ${dir1} ${dir2}| grep "^Only in ${dir1}"| sed 's@^.*: @@')
(cd ${dir1}; ls -l ${LST})

echo files only in $dir2
LST=$(diff ${dir1} ${dir2}| grep "^Only in ${dir2}"| sed 's@^.*: @@')
(cd ${dir2}; ls -l ${LST})

扩展上面的 sed 表达式:
s=搜索和替换
三个“@”分隔表达式(这是传统上用“/”完成的)
^ 匹配一行的开头(强制其余部分不匹配其他地方) .表示任何字符
* 表示前面的表达式 (.==match any char) 0-N 次 “:”是我从差异输出“仅在 X:”中匹配的内容

看妈妈,没有手 - 现在没有“sed”,它的开始越来越不粗糙

XIFS="${IFS}"
IFS=$'\n\r'
for DIFFLINE in $(diff ${dir1} ${dir2}|grep ^Only); do
  case "${DIFFLINE}" in
   "Only in ${dir1}"*)  
    LST1="${LST1} ${DIFFLINE#*:}"
    ;;
   "Only in ${dir2}"*)  
    LST2+="${DIFFLINE#*:}"
    ;;
  esac
done
IFS="${XIFS}"

echo files only in $dir1
(cd ${dir1}; ls -l ${LST1})

echo files only in $dir2
(cd ${dir2}; ls -l ${LST2})

您可能想了解 IFS ......它需要阅读 bash 手册,但它基本上是字段分隔符......默认情况下它们包含空格,我不希望循环被喂行的分数,只是完整的行 - 所以在循环期间我将默认的 IFS 覆盖为换行符和回车符。

顺便说一句,也许您的教授正在阅读 stackoverflow,也许接下来您将不允许使用分号 ;-) ...(回到 'man bash' ...顺便说一句,如果您在 emacs 中执行 'man bash',则更容易阅读 IMO)

【讨论】:

  • 如何格式化?这更接近我的需要。 diff dir1 dir2 | grep a 可以完美地输出 a 中不在 b 中的文件,反之亦然。现在我不知道如何设置它的样式,以便当你使用命令ls -la 时它看起来像输出,如果你能回答我会是金色的:)
  • 我不知道您的格式要求是什么...您没有提供示例输出...我列出的内容显示了哪些文件存在于一个目录中,而不存在于另一个目录中
  • 输出在这个线程的 OP 中,我需要输出来说明,而不是简单地说明 a 中而不是 b 中的文件,它需要采用 ls -l 格式.
  • 谢谢,它有效,请参阅:redd.it/g29zn,OP 中的最后一部分,它有效我只是很想了解代码。
  • 刚看到你的修改,现在我完全一头雾水,一头雾水。我们在课堂上什么都没学到。
【解决方案5】:
awk '{a[$0]++}END{print "some message"; for(i in a)if(a[i]<2){print i}}' <(ls -1 dir2) <(ls -1 dir1)

概念证明

$ ls -1 dir1
file1.txt
file2.txt
file3.txt
file4.txt
file5.txt

$ ls -1 dir2
file1.txt
file3.txt
file4.txt

$ awk '{a[$0]++}END{print "Files in dir1 but NOT in dir2"; for(i in a)if(a[i]<2){print i}}' <(ls -1 dir2) <(ls -1 dir1)
Files in dir1 but NOT in dir2
file5.txt
file2.txt

【讨论】:

    【解决方案6】:
    echo "Files that are in $dir1 but not $dir2"
    for i in "$dir1/"*; do
        [[ -e "$dir2/$i" ]] || (cd "$dir1"; ls -l "$i")
    done
    echo
    

    这是一半。

    如果不使用 Bash,请将 [[ ... ]] 替换为 [ ... ]test ...

    【讨论】:

      猜你喜欢
      • 2011-04-01
      • 2023-03-03
      • 2013-10-01
      • 2012-12-09
      • 2018-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-29
      相关资源
      最近更新 更多