简体   繁体   English

Bash 对两个目录中的文件运行 diff 命令并并排提供自定义的脚本 output?

[英]Bash script to run diff command on files in two directories and provide custom side by side output?

EDIT - Reproducible Code, Output, and Updated Question编辑 - 可重现代码 Output 和更新的问题

#!/bin/bash

# Input Directory
inpd="/home/space user/space test/space dir1"

# Line To Parse
line="/home/space user/space test/space dir1: space file 1.txt"

# Split Line awk -F[:]
echo ""
var1=$(echo "$line" | awk -F[:] '{print $1}')
echo "  echo var1"
echo "  $var1"
echo ""
echo "  printf var1"
printf "%-2s%s" "" $var1

# var1 == inpd
echo ""
echo ""
echo "  var1 == inpd"
if [ var1 == inpd ]; then
  printf "  Match."
else
  printf "  No match."
fi
echo ""

$ scriptname

  echo var1
  /home/space user/space test/space dir1

  printf var1
  /home/spaceuser/spacetest/spacedir1

  var1 == inpd
  No match.

Updated Question - How to define, cast, or properly compare var1 to inpd so it produces a match when the input has spaces?更新的问题- 如何定义、转换或正确比较var1inpd ,以便在输入有空格时产生匹配? If there is a better way to find the match without calling awk it would also solve my problem.如果有更好的方法可以在不调用awk的情况下找到匹配项,它也可以解决我的问题。

I found the clue to solve my question here:我在这里找到了解决问题的线索:

How can I remove all text after a character in bash? 如何删除 bash 中某个字符后的所有文本?

$ script - this gives a Match! $ script - 这给出了匹配!

#!/bin/bash

# Input Directory
inpd="/home/space user/space test/space dir1"

# Line To Parse
line="/home/space user/space test/space dir1: space file 1.txt"

# var1 keeps everything in 'line' before :
var1=${line%:*}
echo ""
echo "$line"
echo "$var1"
printf "$var1"

# "$var1" == "$inpd"
echo ""
if [ "$var1" == "$inpd" ]; then
  printf "  Match."
else
  printf "  No match."
fi
echo ""

EDIT - Why the Long Post?编辑 - 为什么长篇文章?

I made a long post to show my script development effort but the question now reduces to an effort to match any /path with/ or without spaces/dir1 to the same path string or variable extracted from the output lines of the diff command.我发了一篇很长的帖子来展示我的脚本开发工作,但现在的问题简化为将任何/path with/ or without spaces/dir1diff命令的 output 行中提取的相同路径字符串或变量相匹配。 I am using awk with -F[:] as the separator but there may be an alternative way to do it.我使用awk-F[:]作为分隔符,但可能有其他方法可以做到这一点。 I tried to embed some reproducible code above and below with the description Reproducible Code.我试图在上方和下方嵌入一些可重现的代码,并带有可重现代码的描述。 The updated question should be based on the above edit, and the long post is to preserve the new context and the original post.更新的问题应该基于上面的编辑,长帖子是为了保留新的上下文和原始帖子。

For my use cases the custom script is non-recursive;对于我的用例,自定义脚本是非递归的; it would handle spaces in the path or filenames;它将处理路径或文件名中的空格; but as of now it would generate errors for any path or filename containing a colon : character and also for any filename containing a slash / .但截至目前,它会为包含冒号:字符的任何路径或文件名以及包含斜杠/的任何文件名生成错误。 I am not sure what other characters or sequences would produce an error and I don't need a more robust script for my present purposes.我不确定其他哪些字符或序列会产生错误,而且我不需要更强大的脚本来满足我目前的目的。

Spaces in any input path it must be contained in quotes dirt "/path with spaces/dir1" .任何输入路径中的空格都必须包含在引号dirt "/path with spaces/dir1"中。

So far I think if subdirectories appear in only one directory, as shown in my test directory structure, then in the absence of file extensions there is no way to determine whether the name refers to a file or subdirectory.到目前为止,我认为如果子目录只出现在一个目录中,如我的测试目录结构所示,那么在没有文件扩展名的情况下,无法确定该名称是指文件还是子目录。 I intend to use tree to list directories with color to show files and subdirectories and also use the new script dirt to compare files that are the same or different.我打算使用tree来列出带有颜色的目录以显示文件和子目录,并使用新脚本dirt来比较相同或不同的文件。 This will probably work best for directories with few files and not many subdirectories which is my intended use case.这可能最适合文件很少且子目录不多的目录,这是我的预期用例。

EDIT - Desired Output Format (Script Name dirt Using Test Directories Below)编辑 - 所需的 Output 格式(脚本名称dirt使用下面的测试目录)

$ dirt "/home/joe/test dirdiff/dir1" "/home/joe/test dirdiff/dir2"

BOTH    /home/joe/test dirdiff/dir1               /home/joe/test dirdiff/dir2
diff    diff.txt                                  diff.txt
        diffout.txt
        only1.txt
                                                  only2.txt
same    same space.txt                            same space.txt
same    same.txt                                  same.txt
        space 1.txt
                                                  space 2.txt
        subdir1
                                                  subdir2
comd    subdirC                                   subdirC

EDIT - Directory Structure With Spaces (Without:) To Test Script编辑 - 带空格的目录结构(没有:)测试脚本

/home/joe/test dirdiff
├── dir1
│   ├── diff.txt
│   ├── diffout.txt
│   ├── only1.txt
│   ├── same space.txt
│   ├── same.txt
│   ├── space 1.txt
│   ├── subdir1
│   └── subdirC
└── dir2
    ├── diff.txt
    ├── only2.txt
    ├── same space.txt
    ├── same.txt
    ├── space 2.txt
    ├── subdir2
    └── subdirC

EDIT - Output from running diff编辑 - Output 来自运行diff

$ diff -qs "/home/joe/test dirdiff/dir1" "/home/joe/test dirdiff/dir2"

Files /home/joe/test dirdiff/dir1/diff.txt and /home/joe/test dirdiff/dir2/diff.txt differ
Only in /home/joe/test dirdiff/dir1: diffout.txt
Only in /home/joe/test dirdiff/dir1: only1.txt
Only in /home/joe/test dirdiff/dir2: only2.txt
Files /home/joe/test dirdiff/dir1/same space.txt and /home/joe/test dirdiff/dir2/same space.txt are identical
Files /home/joe/test dirdiff/dir1/same.txt and /home/joe/test dirdiff/dir2/same.txt are identical
Only in /home/joe/test dirdiff/dir1: space 1.txt
Only in /home/joe/test dirdiff/dir2: space 2.txt
Only in /home/joe/test dirdiff/dir1: subdir1
Only in /home/joe/test dirdiff/dir2: subdir2
Common subdirectories: /home/joe/test dirdiff/dir1/subdirC and /home/joe/test dirdiff/dir2/subdirC

EDIT - Script Fragment dirt00 Stores diff Output in $diffout编辑 - 脚本片段 dirt00 在$diffout中存储diff Output

  #!/bin/bash
  if [[ -z "$1" || -z "$2" ]]; then
    printf "\n  Type $ dirt00 Dir1 Dir2\n"
  else
    input1="$1"
    input2="$2"
    diffout=$(diff -qs "$1" "$2")
    # Printf '%s\n' "$var" is necessary because printf '%s' "$var" on a
    # variable that doesn't end with a newline then the while loop will
    # completely miss the last line of the variable.
    while IFS= read -r line
      do
        echo $line
      done < <(printf '%s\n' "$diffout")
  fi

EDIT - Output from running dirt00编辑 - Output 来自运行dirt00

$ dirt00 "/home/joe/test dirdiff/dir1" "/home/joe/test dirdiff/dir2"

Files /home/joe/test dirdiff/dir1/diff.txt and /home/joe/test dirdiff/dir2/diff.txt differ
Only in /home/joe/test dirdiff/dir1: diffout.txt
Only in /home/joe/test dirdiff/dir1: only1.txt
Only in /home/joe/test dirdiff/dir2: only2.txt
Files /home/joe/test dirdiff/dir1/same space.txt and /home/joe/test dirdiff/dir2/same space.txt are identical
Files /home/joe/test dirdiff/dir1/same.txt and /home/joe/test dirdiff/dir2/same.txt are identical
Only in /home/joe/test dirdiff/dir1: space 1.txt
Only in /home/joe/test dirdiff/dir2: space 2.txt
Only in /home/joe/test dirdiff/dir1: subdir1
Only in /home/joe/test dirdiff/dir2: subdir2
Common subdirectories: /home/joe/test dirdiff/dir1/subdirC and /home/joe/test dirdiff/dir2/subdirC

EDIT - Reproducible Code Script dirt01编辑 - 可重现的代码脚本dirt01

#!/bin/bash
input1="/home/joe/test dirdiff/dir1"
input2="/home/joe/test dirdiff/dir2"
diffout="Files /home/joe/test dirdiff/dir1/diff.txt and /home/joe/test dirdiff/dir2/diff.txt differ
Only in /home/joe/test dirdiff/dir1: diffout.txt
Only in /home/joe/test dirdiff/dir1: only1.txt
Only in /home/joe/test dirdiff/dir2: only2.txt
Files /home/joe/test dirdiff/dir1/same space.txt and /home/joe/test dirdiff/dir2/same space.txt are identical
Files /home/joe/test dirdiff/dir1/same.txt and /home/joe/test dirdiff/dir2/same.txt are identical
Only in /home/joe/test dirdiff/dir1: space 1.txt
Only in /home/joe/test dirdiff/dir2: space 2.txt
Only in /home/joe/test dirdiff/dir1: subdir1
Only in /home/joe/test dirdiff/dir2: subdir2
Common subdirectories: /home/joe/test dirdiff/dir1/subdirC and /home/joe/test dirdiff/dir2/subdirC"
# Printf '%s\n' "$var" is necessary because printf '%s' "$var" on a
# variable that doesn't end with a newline then the while loop will
# completely miss the last line of the variable.
printf "\n  %-8s%-40s%-40s\n" "BOTH" "$input1" "$input2"
while IFS= read -r line
  do
    #echo $line
    firstword=$(echo "$line" | awk '{print $1}')
    finalword=$(echo "$line" | awk '{print $NF}')
    if   [ $finalword == "differ" ]; then
      snip=${line%" differ"}
      echo "$snip" | awk -F[/] '{printf "  %-8s%-40s%-40s\n","diff",$NF,$NF}'
    elif [ $finalword == "identical" ]; then
      snip=${line%" are identical"}
      echo "$snip" | awk -F[/] '{printf "  %-8s%-40s%-40s\n","same",$NF,$NF}'
    elif [ $firstword == "Common" ]; then
      echo "$line" | awk -F[/] '{printf "  %-8s%-40s%-40s\n","comd",$NF,$NF}'
    else
      echo ""
    fi
  done < <(printf '%s\n' "$diffout")

EDIT - Output from running dirt01编辑 - Output 来自运行dirt01

$ dirt01

  BOTH    /home/joe/test dirdiff/dir1             /home/joe/test dirdiff/dir2
  diff    diff.txt                                diff.txt



  same    same space.txt                          same space.txt
  same    same.txt                                same.txt




  comd    subdirC                                 subdirC

I cannot write dirt02 , to complete the script, without an answer to the updated question at the top of this post.如果没有对本文顶部更新问题的回答,我无法编写dirt02来完成脚本。

I left the original question and post below to preserve the context for the existing answer and comments which are greatly appreciated!我留下了原始问题并在下面发布以保留现有答案和评论的上下文,非常感谢!

NOTE - Original Question and Post Below注意 - 原始问题和下面的帖子

In the two lines starting $NF=="differ" and $NF=="identicial" :在以$NF=="differ"$NF=="identicial"开头的两行中:

(1) How do I split the file name and extension from the directory using either identical awk variable shown below as $2 or $4 and then output the filename.ext in the printf command? (1) 如何在printf命令中使用下面显示为$2$4的相同 awk 变量,然后使用 output filename.ext 从目录中拆分文件名和扩展名?

dirdiff - bash script dirdiff - bash 脚本

  #!/bin/bash
  if [[ -z $1 || -z $2 ]]; then
    printf "\n  Type $ dirdiff Dir1 Dir2\n"
  else
    LEFT=$1
    LEFT+=:
    RGHT=$2
    RGHT+=:
    printf "\n  %-8s%-40s%-40s\n" "" "$1" "$2"
    printf "  %-8s%-40s%-40s\n\n" "" "$LEFT" "$RGHT"
    diff -qs $1 $2
    echo ""
    printf "\n%-8s%-40s%-40s\n" "INFO" "$1" "$2"
    diff -qs $1 $2 | awk -v L=$LEFT -v R=$RGHT \
                     '$NF=="differ" {printf "%-8s%-40s%-40s\n","diff", $2, $4} \
                      $NF=="identical" {printf "%-8s%-40s%-40s\n","same", $2, $4} \
                      $3==L {printf "%-8s%-40s\n","", $4} \
                      $3==R {printf "%-8s%-40s%-40s\n","", "", $4}'
  fi

This is the debug and develop script which runs command $ diff -qs $1 $2 twice.这是运行命令$ diff -qs $1 $2两次的调试和开发脚本。 The first time shows the raw output. The second time pipes output to awk where I am trying to parse lines and format output on the command line.第一次显示原始 output。第二次通过管道将 output 传输到 awk,我试图在命令行上解析行和格式 output。 My questions relate to the final five lines in the script.我的问题与脚本的最后五行有关。 EDIT: I solved the printf syntax problem in awk as shown in the code.编辑:如代码所示,我解决了 awk 中的printf语法问题。

Run dirdiff on command line gives the following command line output在命令行上运行 dirdiff 给出以下命令行 output

$ dirdiff /usr/local/adm/sys /mnt/ssdroot/home/joe/admin/sys

          /usr/local/adm/sys                      /mnt/ssdroot/home/joe/admin/sys
          /usr/local/adm/sys:                     /mnt/ssdroot/home/joe/admin/sys:

Only in /mnt/ssdroot/home/joe/admin/sys: bashrc.txt
Only in /usr/local/adm/sys: debpkgs.txt
Files /usr/local/adm/sys/direnv.txt and /mnt/ssdroot/home/joe/admin/sys/direnv.txt differ
Only in /usr/local/adm/sys: dpiDec2022.txt
Only in /mnt/ssdroot/home/joe/admin/sys: mypkgs.txt
Only in /mnt/ssdroot/home/joe/admin/sys: pyenv.txt
Files /usr/local/adm/sys/ssh.txt and /mnt/ssdroot/home/joe/admin/sys/ssh.txt are identical
Files /usr/local/adm/sys/usbquirks.txt and /mnt/ssdroot/home/joe/admin/sys/usbquirks.txt differ


INFO    /usr/local/adm/sys                      /mnt/ssdroot/home/joe/admin/sys
                                                bashrc.txt
        debpkgs.txt
diff    /usr/local/adm/sys/direnv.txt           /mnt/ssdroot/home/joe/admin/sys/direnv.txt
        dpiDec2022.txt
                                                mypkgs.txt
                                                pyenv.txt
same    /usr/local/adm/sys/ssh.txt              /mnt/ssdroot/home/joe/admin/sys/ssh.txt
diff    /usr/local/adm/sys/usbquirks.txt        /mnt/ssdroot/home/joe/admin/sys/usbquirks.txt

Desired Command Line Output Format (Duplicated at Top)所需的命令行 Output 格式(在顶部重复)

$ dirdiff /usr/local/adm/sys /mnt/ssdroot/home/joe/admin/sys

INFO    /usr/local/adm/sys                        /mnt/ssdroot/home/joe/admin/sys
                                                  bashrc.txt
        debpkgs.txt
diff    direnv.txt                                direnv.txt
        dpiDec2022.txt
                                                  mypkgs.txt
                                                  pyenv.txt
same    ssh.txt                                   ssh.txt
diff    usbquirks.txt                             usbquirks.txt

Hope this helps.希望这可以帮助。 I think the sub function is what you are asking about for the basename function.我认为sub function 是您要询问的basename function。

Good luck!祝你好运!

    diff -qs $1 $2 | gawk -v L=$1 -v R=$2 \
      'BEGIN { printf "\n%-8s%-40s%-40s\n", "INFO", L, R } \
         $NF=="differ" { sub( /.*\//,"",$4) ; printf "%-8s%-40s%-40s\n", "diff", $4, $4 } \
         $NF=="identical" { sub( /.*\//,"",$4) ; printf "%-8s%-40s%-40s\n", "same", $4, $4 } \
         $3==L":" { sub( /.*\//,"",$4) ; printf "%-8s%-40s%-40s\n", "only", $4, "" } \
         $3==R":" { sub( /.*\//,"",$4) ; printf "%-8s%-40s%-40s\n", "only", "", $4 } '
INFO    dir1                                    dir2                                    
only                                            bashrc.txt                              
only    debpkgs.txt                                                                     
diff    direnv.txt                              direnv.txt                              
only    dpiDec2022.txt                                                                  
only                                            mypkgs.txt                              
only                                            pyenv.txt                               
same    ssh.txt                                 ssh.txt                                 
diff    usbquirks.txt                           usbquirks.txt 

Directory Structure With Spaces (Without:) To Test Script带空格的目录结构(不带:)测试脚本

/home/joe/test dirdiff
├── dir1
│   ├── diff.txt
│   ├── diffout.txt
│   ├── only1.txt
│   ├── same space.txt
│   ├── same.txt
│   ├── space 1.txt
│   ├── subdir1
│   └── subdirC
└── dir2
    ├── diff.txt
    ├── only2.txt
    ├── same space.txt
    ├── same.txt
    ├── space 2.txt
    ├── subdir2
    └── subdirC

Reproducible Script Works for Paths & Names Containing Spaces but Not Colons可重现的脚本适用于包含空格但不包含冒号的路径和名称

#!/bin/bash
input1="/home/joe/test dirdiff/dir1"
input2="/home/joe/test dirdiff/dir2"
diffout="Files /home/joe/test dirdiff/dir1/diff.txt and /home/joe/test dirdiff/dir2/diff.txt differ
Only in /home/joe/test dirdiff/dir1: diffout.txt
Only in /home/joe/test dirdiff/dir1: only1.txt
Only in /home/joe/test dirdiff/dir2: only2.txt
Files /home/joe/test dirdiff/dir1/same space.txt and /home/joe/test dirdiff/dir2/same space.txt are identical
Files /home/joe/test dirdiff/dir1/same.txt and /home/joe/test dirdiff/dir2/same.txt are identical
Only in /home/joe/test dirdiff/dir1: space 1.txt
Only in /home/joe/test dirdiff/dir2: space 2.txt
Only in /home/joe/test dirdiff/dir1: subdir1
Only in /home/joe/test dirdiff/dir2: subdir2
Common subdirectories: /home/joe/test dirdiff/dir1/subdirC and /home/joe/test dirdiff/dir2/subdirC"
printf "\n  %-8s%-40s%-40s\n" "BOTH" "$input1" "$input2"
# Printf '%s\n' "$var" is necessary because printf '%s' "$var" on a
# variable that doesn't end with a newline then the while loop will
# completely miss the last line of the variable.
while IFS= read -r line
  do
    #echo $line
    firstword=$(echo "$line" | awk '{print $1}')
    finalword=$(echo "$line" | awk '{print $NF}')
    if   [[ "$finalword" == "differ" ]]; then
      snip=${line%" differ"}
      echo "$snip" | awk -F[/] '{printf "  %-8s%-40s%-40s\n","diff",$NF,$NF}'
    elif [[ "$finalword" == "identical" ]]; then
      snip=${line%" are identical"}
      echo "$snip" | awk -F[/] '{printf "  %-8s%-40s%-40s\n","same",$NF,$NF}'
    elif [[ "$firstword" == "Common" ]]; then
      echo "$line" | awk -F[/] '{printf "  %-8s%-40s%-40s\n","comd",$NF,$NF}'
    elif [[ "$firstword" == "Only" ]]; then
      snip=${line#"Only in "}
      mdir=${snip%:*}
      name=${snip#*:}
      name=${name# *}
      if [[ "$mdir" == "$input1" ]]; then
        printf "  %-8s%-40s\n" "" "$name"
      else
        printf "  %-8s%-40s%-40s\n" "" "" "$name"
      fi
    else
      echo ""
    fi
  done < <(printf '%s\n' "$diffout")

$ scriptname

  BOTH    /home/joe/test dirdiff/dir1             /home/joe/test dirdiff/dir2
  diff    diff.txt                                diff.txt
          diffout.txt
          only1.txt
                                                  only2.txt
  same    same space.txt                          same space.txt
  same    same.txt                                same.txt
          space 1.txt
                                                  space 2.txt
          subdir1
                                                  subdir2
  comd    subdirC                                 subdirC

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM