为什么出现“join: extra operand '/dev/fd/62'”错误?

为什么出现“join: extra operand '/dev/fd/62'”错误?

我有一个脚本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")

和两个文件

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

为什么最后一个命令失败?谢谢。

$ 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'

答案1

"$outer"是一个带引号的标量变量,因此它始终扩展为一个参数。如果为空或未设置,它仍然会扩展为一个空参数join(当您使用 调用脚本时-o2,这是一个-a 2参数,而不是两个参数-a2)。

join可能是 GNU,join因为它接受非选项参数之后的选项。当为空时,这"$outer"是一个非选项参数,因为它不以-so 开头,被视为文件名,并join抱怨提供了它不期望的第三个文件名。

如果您想要一个具有可变数量参数的变量,请使用数组:

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

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

虽然在这里你也可以这样做:

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

或者:

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

zsh(除了 sh/ksh 模拟之外,该功能不起作用)。

其他一些注意事项:

  • join -t '\t'不起作用。您需要delim=$'\t'将文字 TAB 存储在$delim
  • 请记住在将任意参数传递给命令时使用--(或在可能的情况下使用重定向)。所以sort -- "$f1"或者更好地sort < "$f1"代替sort "$f1".
  • 算术扩展也受到 split+glob 的影响,因此也应该被引用 ( shift "$((OPTIND - 1))") (这里不是问题,因为您使用的bash不是$IFS从环境继承的,并且您没有IFS在脚本的前面进行修改,但仍然是很好的实践)。

相关内容