Why do I have “join: extra operand ‘/dev/fd/62′” error?

I have a script equijoin2:

#! /bin/bash

# default args                                                                                                                                                                    
delim="," # CSV by default                                                                                                                                                        
outer=""
outerfile=""
# Parse flagged arguments:                                                                                                                                                        
while getopts "o:td:" flag
do
  case $flag in
    d) delim=$OPTARG;;
    t) delim="t";;
    o) outer="-a $OPTARG";;
    ?) exit;;
  esac
done
# Delete the flagged arguments:                                                                                                                                                   
shift $(($OPTIND -1))
# two input files                                                                                                                                                                 
f1="$1"
f2="$2"
# cols from the input files                                                                                                                                                       
col1="$3"
col2="$4"


join "$outer" -t "$delim" -1 "$col1" -2 "$col2" <(sort "$f1") <(sort "$f2")

and two files

$ cat file1
c c1
b b1
$ cat file2
a a2
c c2
b b2

Why does the last command fail? Thanks.

$ equijoin2 -o 2  -d " " file1 file2 1 1
a a2
b b1 b2
c c1 c2
$ equijoin2 -o 1  -d " " file1 file2 1 1
b b1 b2
c c1 c2
$ equijoin2   -d " " file1 file2 1 1
join: extra operand '/dev/fd/62'

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

"$outer" is a quoted scalar variable so it always expands to one argument. If empty or unset, that still expands to one empty argument to join (and when you call your script with -o2, that’s one -a 2 argument instead of the two arguments -a and 2).

Your join is probably GNU join in that it accepts options after non-option arguments. That "$outer" is a non-option argument when empty as it doesn’t start with - so is treated as a file name and join complains about the third file name provided which it doesn’t expect.

If you want a variable with a variable number of arguments, use an array:

outer=()
...
(o)
   outer=(-a "$OPTARG");;

...
join "${outer[@]}"

Though here you could also do:

outer=
...
(o)
   outer="-a$OPTARG";;
...
join ${outer:+"$outer"} ... <(sort < "$f1") <(sort < "$f2")

Or:

unset -v outer
...
(o)
   outer="$OPTARG";;
...
join ${outer+-a "$outer"} ...

(that one doesn’t work in zsh except in sh/ksh emulation).

Some other notes:

  • join -t 't' doesn’t work. You’d need delim=$'t' to store a literal TAB in $delim
  • Remember to use -- when passing arbitrary arguments to commands (or use redirections where possible). So sort -- "$f1" or better sort < "$f1" instead of sort "$f1".
  • arithmetic expansions are also subject to split+glob so should also be quoted (shift "$((OPTIND - 1))") (here not a problem though as you’re using bash which doesn’t inherit $IFS from the environment and you’re not modifying IFS earlier in the script, but still good practice).


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x