[英]Bash script to run diff command on files in two directories and provide custom side by side output?
编辑 - 可重现代码 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.
更新的问题- 如何定义、转换或正确比较var1
与inpd
,以便在输入有空格时产生匹配? 如果有更好的方法可以在不调用awk
的情况下找到匹配项,它也可以解决我的问题。
我在这里找到了解决问题的线索:
$ 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 ""
编辑 - 为什么长篇文章?
我发了一篇很长的帖子来展示我的脚本开发工作,但现在的问题简化为将任何/path with/ or without spaces/dir1
从diff
命令的 output 行中提取的相同路径字符串或变量相匹配。 我使用awk
和-F[:]
作为分隔符,但可能有其他方法可以做到这一点。 我试图在上方和下方嵌入一些可重现的代码,并带有可重现代码的描述。 更新的问题应该基于上面的编辑,长帖子是为了保留新的上下文和原始帖子。
对于我的用例,自定义脚本是非递归的; 它将处理路径或文件名中的空格; 但截至目前,它会为包含冒号:
字符的任何路径或文件名以及包含斜杠/
的任何文件名生成错误。 我不确定其他哪些字符或序列会产生错误,而且我不需要更强大的脚本来满足我目前的目的。
任何输入路径中的空格都必须包含在引号dirt "/path with spaces/dir1"
中。
到目前为止,我认为如果子目录只出现在一个目录中,如我的测试目录结构所示,那么在没有文件扩展名的情况下,无法确定该名称是指文件还是子目录。 我打算使用tree
来列出带有颜色的目录以显示文件和子目录,并使用新脚本dirt
来比较相同或不同的文件。 这可能最适合文件很少且子目录不多的目录,这是我的预期用例。
编辑 - 所需的 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
编辑 - 带空格的目录结构(没有:)测试脚本
/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
编辑 - 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
编辑 - 脚本片段 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
编辑 - 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
编辑 - 可重现的代码脚本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")
编辑 - 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
如果没有对本文顶部更新问题的回答,我无法编写dirt02
来完成脚本。
我留下了原始问题并在下面发布以保留现有答案和评论的上下文,非常感谢!
注意 - 原始问题和下面的帖子
在以$NF=="differ"
和$NF=="identicial"
开头的两行中:
(1) 如何在printf
命令中使用下面显示为$2
或$4
的相同 awk 变量,然后使用 output filename.ext 从目录中拆分文件名和扩展名?
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
这是运行命令$ diff -qs $1 $2
两次的调试和开发脚本。 第一次显示原始 output。第二次通过管道将 output 传输到 awk,我试图在命令行上解析行和格式 output。 我的问题与脚本的最后五行有关。 编辑:如代码所示,我解决了 awk 中的printf
语法问题。
在命令行上运行 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
所需的命令行 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
希望这可以帮助。 我认为sub
function 是您要询问的basename
function。
祝你好运!
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
带空格的目录结构(不带:)测试脚本
/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
可重现的脚本适用于包含空格但不包含冒号的路径和名称
#!/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.