Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to nested loop 2 files then compare columns without using `while read`?

There are 2 files has same structure.Output difference of each other columns, based on same value of specific column.

##!/bin/bash
set -e

result_dir='/home/folder1'

#2 test files
cat << EOF > $result_dir/old
1 a /home
5 b /home/me
6 e /home/me/file 2
3 c /home/oth
EOF
cat << EOF > $result_dir/new
1 a /home
4 b /home/me
6 f /home/me/file 2
5 c /home/oth/file
EOF

#loop
changed=()
while read -r -u 5 OWNER GROUP FOLDER; do
    temp=''
    while read -r -u 6 OWNER_NEW GROUP_NEW FOLDER_NEW; do
    #exist in both old & new
    if [[ "$FOLDER" == "$FOLDER_NEW" ]]; then
        temp+=$FOLDER
        if [[ $OWNER != $OWNER_NEW ]]; then
        temp+=$sep$OWNER_NEW
        else
        temp+=$sep
        fi
        if [[ $GROUP != $GROUP_NEW ]]; then
        temp+=$sep$GROUP_NEW
        else
        temp+=$sep       
        fi
        #changed?
        if [[ "$(echo -e "${temp}" | sed -e 's/[[:space:]]*$//')" != $FOLDER ]] ; then
        changed+=($temp)
        fi
        break
    fi
    done 6<$result_dir/acl_folder_new

#old loop
done 5<$result_dir/acl_folder_old

echo -e "${changed[@]}"

Output as below:

/home/me 4
/home/me/file 2  f

Everything is ok, but speed too slow when file contain more than 10000+ lines as other post1,post2

How to nested loop 2 files then compare columns without using while read?

like image 448
kittygirl Avatar asked Nov 27 '25 12:11

kittygirl


1 Answers

The term "folder" is from Windows. In Unix the equivalent is a "directory". The following will accommodate spaces in your directory names (as you have in your sample input with /home/me/file 2 but that's not adequate to test that a given script accommodates it) and will work using any awk in any shell on every Unix box:

$ cat tst.sh
#!/usr/bin/env bash

result_dir='/home/directory1'
mkdir -p "$result_dir" || exit

#2 test files
cat << EOF > "$result_dir/old"
1 a /home
5 b /home/me
6 e /home/me/file 2
3 c /home/oth
EOF

cat << EOF > "$result_dir/new"
1 a /home
4 b /home/me
6 f /home/me/file 2
5 c /home/oth/file
EOF

awk '
{
    match($0,/^([^ ]+ ){2}/)
    dir = substr($0,RLENGTH+1)
    $0 = substr($0,1,RLENGTH-1)
}
NR==FNR {
    olds[dir] = $0
    next
}
dir in olds {
    split(olds[dir],old)
    for (i=1; i<=NF; i++) {
        if ($i != old[i]) {
            print dir, $i
        }
    }
}
' "$result_dir/old" "$result_dir/new"

$ ./tst.sh
/home/me 4
/home/me/file 2 f
like image 195
Ed Morton Avatar answered Nov 29 '25 03:11

Ed Morton



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!