2

I want to write a script that takes text files as arguments and merge them.

  • All the files consist of grouped lines divided by empty lines.
  • The script can take more than 2 arguments
  • The files can include more groups
  • If the files have different number of groups, when the groups in one file ends, the remaining groups in the other file should be added one after another in order like this: 111-211-121-122-221-222-223-131-132-133-231-241-251-261-271

    I want to merge the files to stdout and the output should be "1st group from the first file then 1st group from the second file then 2nd group from 1th file..."

    Let's say that the lines in the files are formatted as "file-number_group-number_line-number" like this:

01_01_01

01_02_01
01_02_02
01_02_03

01_03_01
02_01_01
02_01_02

02_02_01

02_03_01
02_03_02

Then the output should be:

01_01_01
02_01_01
01_02_01
01_02_02
01_02_03
02_02_01
01_03_01
02_03_01
02_03_02

I tried using paste but I ran into problems.

#!/bin/bash
paste -d "\n\n" $1 $2  | sed '/^[[:space:]]*$/d'

and the output is this:

01_01_01
02_01_01
02_01_02
01_02_01
01_02_02
02_02_01
01_02_03
02_03_01
01_03_01
02_03_02

Also I want to see which file each line came from so how can I add the file numbers to the beginning of each line like this :

1:01_01_01
2:02_01_01
1:01_02_01
1:01_02_02
1:01_02_03
2:02_02_01
1:01_03_01
2:02_03_01
2:02_03_02

2 Answers 2

1

In pure bash this can be done with the help of file descriptor.

file1="$1"; file2="$2"
__print() {
  [[ $1 ]] && { printf '1: %s\n' "$1"; }
  [[ $2 ]] && { printf '2: %s\n' "$2"; }
}
if [[ $file1 ]] && [[ $file2 ]]; then
    while true; do
      read -r f1 <&3 || break
      read -r f2 <&4 || break
      __print "$f1" "$f2"
    done 3<"${file1}" 4<"${file2}"
else
    echo "Usage: '$0 <file1> <file2>'"
fi

Will give you output as follows:

1: 01_01_01
2: 02_01_01
2: 02_01_02
1: 01_02_01
1: 01_02_02
2: 02_02_01
1: 01_02_03
2: 02_03_01
1: 01_03_01
2: 02_03_02
5
  • Gives this error - line 10: grp1: No such file or directory
    – arty
    Dec 10, 2019 at 18:51
  • Thanks now it works. But i tried to print a version without the file numbers by deleting "1:" part from "printf '%s\n'" and now it is without the number but the order is problematic again.
    – arty
    Dec 10, 2019 at 18:59
  • It worked nicely when I used the example given in the question. What version you would like to print ? Are you reading it from the file? If so, then try adding it in the read -r option maybe.
    – Rakib Fiha
    Dec 10, 2019 at 19:06
  • I wanted to get the first output in my question so I deleted 1: from your print() function. It deleted the file numbers at the beginning of each line but also the order got messy.
    – arty
    Dec 10, 2019 at 19:18
  • I just tried what you have said, it worked fine for me. __print() { [[ $1 ]] && { printf '%s\n' "$1"; } [[ $2 ]] && { printf '%s\n' "$2"; } }
    – Rakib Fiha
    Dec 10, 2019 at 19:21
1

You can do it with POSIX grep across shells and implementations:

grep -v '^\s*$' file1 file2 file...

For two files based on your input the output is:

file1:01_01_01
file1:01_02_01
file1:01_02_02
file1:01_02_03
file1:01_03_01
file2:02_01_01
file2:02_01_02
file2:02_02_01
file2:02_03_01
file2:02_03_02

you can then use sed and sort for further formatting.

In a script:

#!/bin/sh
grep -v '^\s*$' "$@"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .