2

I have sorted data like this:

a
a f
b
c
c e
d
f z

Essentially these lines are each lists of aliases for the same thing, and they need to be merged. This is simplified. In case it matters in the real case I am handling filepaths that have moved and need to know what filepaths are essentially the same. The input has 1 column for the initial file and 2 columns when a file was renamed. Looking for an output like this:

a f z
b
c e
d

This is for a bash script on a typical Linux system, so any mostly standard tool will do. I have tried a few awk scripts from other questions dealing with this subject thus far and have not found good results.

2

Awk solution:

awk '{ 
         if (NF == 2) {
             if ($1 in r) { 
                 a[r[$1]] = a[r[$1]] OFS $2; next 
             } 
             a[$1] = $2; r[$2] = $1; 
         } 
         else a[$1]; 
     }
     END{ for (i in a) print i, a[i]  }' file
  • NF == 2 - condition indicating a record with 2 fields (NF - total number of fields)
  • a - array which holds either "standalone" filenames (which haven't been renamed) like b and d or relation between the initial filename and its renamed version (e.g. a -> f)
  • r - array which holds the opposite relation "renamed filename" -> "initial filename" (e.g. f -> a)

The output:

a f z
b 
c e
d 

In case if some filename could have been renamed more than once - use the following extended solution:

awk '{ 
         if (NF == 2) {
             if ($1 in r) { 
                 a[r[$1]] = a[r[$1]] OFS $2; r[$2] = r[$1];
             } 
             else { a[$1] = $2; r[$2] = $1 } 
         } 
         else a[$1]; 
     }
     END{ for (i in a) print i, a[i]  }' file
  • This solution isn't correct. Try apply it to the input data from my answer. It can't process chains, which longer than 3 items. – MiniMax Mar 10 '18 at 10:43
  • @MiniMax, I wouldn't be so categorical. Telling that something is definitely incorrect is subjective approach. Enjoy my update. (And one secret hint - your solution is a bit slower) – RomanPerekhrest Mar 10 '18 at 11:22
  • 1
    I went back and forth between this and @MiniMax's answer testing with the full data set (and finding quirks I did not expect like renames back into previously mentioned files). This answer works best as long as the input data is in "historical" order - not as much when the data is alphabetically sorted or in reverse order. – kcghost Mar 11 '18 at 18:03
  • @kcghost, yes, this approach is for a proper chronological list – RomanPerekhrest Mar 11 '18 at 18:19
  • @kcghost Yes, my solution does not handle renaming to the previously occurred name. It works only with unique names in each renaming chain. This answer is better in this case. – MiniMax Mar 11 '18 at 18:42
1
gawk '
{
    arr[cnt][0] = $1    
    arr[cnt++][1] = $2  
}
END {
    for(i = 0; i < cnt; i++) {
        if(!arr[i][0]) continue

        next_name = arr[i][0]

        for(j = i; j < cnt; j++) {
            if(arr[j][0] != next_name) continue

            if(arr[j][1]) {
                next_name = arr[j][1]
                delete arr[j]
            }
            printf "%s ", next_name

        }
        print ""
    }
}' cnt=0 input.txt

Input (complicated for testing)

u
a
a f
b
c
c e
d
c
f g
g a
a i
i j
a
a z
z w

Output

u 
a f g a i j 
b 
c e 
d 
c 
a z w 
  • This seems to work better for alphabetically sorted or randomly sorted input. However it misses the first entry if that entry is not a renamed entry. It also outputs a "1" for some edge cases, I believe when files are reintroduced. – kcghost Mar 11 '18 at 18:21
  • @kcghost Check another version. I tried to take into account all cases, which you mentioned: reintroducing the same name again, like creating the new file with the previously used, but already renamed name or if the old file with this name was removed, returning to the same name, after multiple renaming to the different filenames (a, then f, then z, then returning to a again). – MiniMax Mar 11 '18 at 23:55
  • Interesting approach, I had not expected this interpretation where you have a new entry for different chains. I expect this will be helpful to someone, but I think I will only change the accepted answer at this point for a more generic solution that ignores the file naming input aspect and just "merges lists based on duplicate values". I think in retrospect I shouldn't have mentioned my specific case. Either of the current solutions, while very helpful to my specific case, are not very helpful to someone searching the site for a generic solution. – kcghost Mar 12 '18 at 12:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.