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 needdelim=$'t'to store a literal TAB in$delim- Remember to use
--when passing arbitrary arguments to commands (or use redirections where possible). Sosort -- "$f1"or bettersort < "$f1"instead ofsort "$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 usingbashwhich doesn’t inherit$IFSfrom the environment and you’re not modifyingIFSearlier 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