0
cat << EOF > test.sh

cat $FILEA $FILEB | sort -k1,1 -k2,2n | mergeBed -i - | awk -F\\t '{print $1 "\t" NR "\t\t" $2 "\t" $3 "\t\t.\t\t" NR}' > unionpeaks.gff

EOF

I found $1 $2 $3 can not pass to awk in output file. I got:

cat /file1.narrowPeak /file2.narrowPeak | sort -k1,1 -k2,2n | mergeBed -i - | awk -F\t '{print  "\t" NR "\t\t"  "\t"  "\t\t.\t\t" NR}' > merge.gff
Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • This really seems to be about [passing and setting variables in a heredoc](https://unix.stackexchange.com/questions/405250/passing-and-setting-variables-in-a-heredoc) – steeldriver Mar 13 '22 at 17:32

2 Answers2

3

The $1, $2 and $3 in the here document are substituted as it catted. At this point the parameters have no meaning, so are replaced by null strings. Consider:

bash-4.4$ cat << EOF > test2.sh
> >$1<>$2<>$3<
> EOF
bash-4.4$ cat test2.sh 
><><><
  • 1
    ... so the solution is to escape the dollar signs or quote the document, whichever is most meaningful to the application. – Kusalananda Mar 13 '22 at 18:05
  • @they, if using `cat << 'EOF'`, the `cat $FILEA $FILEB | sort -k1,1 -k2,2n` would also have to be changed to `cat -- "$FILEA" "$FILEB" | sort -k1,1 -k2,2n` or better `sort -k1,1 -k2,2n -- "$FILEA" "$FILEB"`. With `cat << EOF`, that `cat $FILEA $FILEB` (where those variables are expanded by the shell that generates the `test.sh` file) would also be problematic unless those variables are guaranteed not to contain characters special to the shell. – Stéphane Chazelas Mar 13 '22 at 19:39
1

First of all, it's easy to simply point out that the method is a bit redundant. But one thing at a time...

When using cat <<EOF, anything within that can be parsed as an inline command or substitution will be parsed as such. That means that stuff like $1 and $(...) will first be evaluated before the heredoc is created. If you wish to avoid that, the easiest option is to single quote the EOF as such:

cat <<'EOF'
heredoc string stuff in here
EOF

But I'm not sure that is what you want. For whatever you wish to appear in a file, just pipe it there:

cat $FILEA $FILEB | sort -k1,1 -k2,2n | mergeBed -i - | awk -F\\t '{print $1 "\t" NR "\t\t" $2 "\t" $3 "\t\t.\t\t" NR}' > unionpeaks.gff

The heredoc is not necessary. Now, let's look at the cammand per se:

sort -k1,1 -k2,2n -- "$FILEA" "FILEB" | mergeBed -i - | awk -v FS="\t" -v OFS="\t" '{ print $1, NR, "", $2, $3, "", ".", "", NR }' > unionpeaks.gff

cat is simply unnessecary. sort can take file names as input, so no need for an extra call -- I just added a -- to make sure that it doesn't break with files that start with a - (dash). Also, it seems you want tab delimited, so set the OFS (output field separator) to tab. The expected delimiter seems a bit weird as you want double tab for some of them, hence the use of zero-byte strings, i.e. "".

If you simply want that command in a script, then just edit a script file to conatain the script. Combine the EOF learning with the script improvement if the learning about heredocs is the intended purpose. :)

Kaffe Myers
  • 404
  • 2
  • 5