Script for linking files with paths in 2 text files

I have 2 txt files, 1.txt and 2.txt which contain the paths to files that need to be linked.

Example 1.txt:

/root/001/folder2/image4.nii.gz
/root/002/folder2/image4.nii.gz

Example 2.txt:

/root/001/folder2/image5.nii.gz
/root/002/folder2/image5.nii.gz

Each line represents images from one subject, so i need to make a link to image4.nii.gz called image5_done.nii.gz (same name as image5, but with _done at the end). Links should be made in the same directory for each subject. I'm very new to scripting and this is something I've been unsuccessfully struggling with for a while. Help is much appreciated.

Can you show us what you have tried?

for file in `cat 1.txt`; do
	ln -si $file ./root/00*/folder2/*5*_done.nii.gz
done

The way I use the variable ${COUNT} in the awk command isn't proper (and that will be pointed out by others since I can never remember how it goes) but this works:

#!/bin/ksh
COUNT=1
while read LNKFILE1
do
    LNKFILE2=$(awk 'NR == "'${COUNT}'"' 2.txt)
    ln -si ${LNKFILE1} ${LNKFILE2}_done
    COUNT=$(($COUNT + 1))
done < 1.txt

@LeftoverStew, tt is a bit more complicated than that. A link in the same directory, means making the link to the file name only (without the path). Also, there are all sorts of error condition that might occur. Also since the match is made line for line by the content of the files, they need to be read at the same time.

For example:

complain() {
  printf "%s\n" "$*"
  continue
}

while read file && read link<&3
do
  # determine directories
  dir_file=${file%/*}
  dir_link=${link%/*}

  # determine name of new link
  new_link=${link%.*.*}_done.${link#*.}

  # determine name the local link should point to
  local_file=${file##*/}
  
  # complain if there are things wrong
  [ -e "$file" ]                || complain "file $file does not exist"
  [ "$dir_file" = "$dir_link" ] || complain "The directories of $file and $link are not the same, so a local symlink cannot be made"
  [ ! -e "$new_link" ]          || complain "An entry for $new_link already exists"

  # create the link
  ln -s "$local_file" "$new_link"
done < 1.txt 3<2.txt
3 Likes

Scrutinizer, you are an awesome human being. I am forever grateful, it does exactly what I wanted!!!

Hi Scrutinizer,

Could you please explain about file descriptor 3 ?

Thanks
Pravin

Hi Pravin, I could have used any file descriptor, but I used 3 because 0,1 and 2 are taken by stdin, stdout and stderr. At the bottom of the loop I am redirecting file descriptor 3 to take its input from the file "2.txt" so that is is local to the loop, meaning that once the loop finishes the file gets closed and the redirect is ended.

Inside the loop I am using two read statements, the first is reading from stdin, which is the default, that is why it can be left out, but I could have written:

while read file<&0 && read link<&3

and the other is readiing from the file descriptor defined at the bottom of the loop.

---
Likewise I also could have written:

done 0<file1 3<file2
1 Like