1

I have files in a directory (/home/user/example) that I need to verify and match. Each file has a control and data file. I want to check if for each file there is a corresponding file of the other. For example, if example.ctl has a match with example.out or example.out has a corresponding file with example.ctl.

I had written a nested for loop and with many if else statements. But this seemed to be far too complex for a basic check like this. I wanted to see if anyone had a better solution.

Example files in directory:

example.ctl
example.out  
example_1.ctl
example_1.out  
example_2.ctl
example_2.out  
5
  • 4
    Any bit of chance to see your actual code 'for loop' ??? Commented Mar 21, 2018 at 18:23
  • @don_crissti Upvoted your comment by mistake; it's not a duplicate because the other question said "there are .A files without .B files, but no .B files without .A files." Commented Mar 21, 2018 at 20:51
  • @l0b0 - all right... though the Q here is vague. OP, what is the expected output here ? List unpaired file names regardless of their extension ? Commented Mar 21, 2018 at 20:59
  • That would be my guess Commented Mar 21, 2018 at 21:15
  • Yes that's what I'm trying to accomplish Commented Mar 22, 2018 at 14:11

4 Answers 4

2
comm <(basename -a -s.ctl *.ctl | sort) <(basename -a -s.out *.out | sort)

See comm(1), espacially the flags -12 will list only files with both suffixes.

1

First variant

It iterates through all filenames and check each file, does it has a pair or not and prints a corresponding message.

for i in *; do
    base=${i%.*}
    if [ -e "${base}.out" -a -e "${base}.ctl" ]; then
        printf 'file "%s" has a pair\n' "$i"
    else
        printf 'file "%s" has not a pair\n' "$i"
    fi  
done

Second variant

It iterates only through .ctl files and check does the current .ctl file have a pair - the .out file. So, it prints only paired files, omitting the rest - unpaired files.

for i in *.ctl; do
    base=${i%.*}
    if [ -e "${base}.out" ]; then
        printf 'file "%s" has a pair "%s"\n' "$i" "${base}.out"
    fi
done
0

You are trying to detect missing .ctl and .out files, so you need to check both ways. An easy way to do this (if your file names contain no special characters, including whitespace, and contain only a single dot) is to

  1. find all files with find . -type f,
  2. remove the extension from each of them with cut --delimiter=. --fields=1,
  3. sort --unique to remove duplicates,
  4. loop through them with while read name, and finally
  5. check if each of the files exist with [[ -e "${name}.ctl" ]] || echo "${name}.ctl" >&2 and the same for .out.
0

You can loop across the files and derive the expected filenames for the Output and Control files. Once you've done that you can check that both exist:

for item in *.out *.ctl
do
    base="${item%???}"
    out="$base.out" ctl="$base.ctl"
    [ -f "$out" -a ! -f "$ctl" ] && echo "$out is missing $ctl" >&2
    [ -f "$ctl" -a ! -f "$out" ] && echo "$ctl is missing $out" >&2
done

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.