Por que eu tenho o erro “join: extra operand '/ dev / fd / 62'”?

1

Eu tenho um 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")

e dois arquivos

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

Por que o último comando falha? Obrigado.

$ 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'
    
por Tim 24.07.2018 / 07:40

1 resposta

4

"$outer" é uma variável escalar entre aspas, de modo que sempre se expande para um argumento. Se vazio ou não definido, isso ainda se expande para um argumento vazio para join (e quando você chama seu script com -o2 , esse é um argumento -a 2 em vez dos dois argumentos -a e 2 ).

O seu join é provavelmente o GNU join em que ele aceita opções após argumentos não-opcionais. Esse "$outer" é um argumento não opcional quando vazio, pois não começa com - , portanto, é tratado como um nome de arquivo e join reclama sobre o terceiro nome de arquivo fornecido, o que não é esperado.

Se você quiser uma variável com um número variável de argumentos, use uma matriz:

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

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

Embora aqui você também possa fazer:

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

Ou:

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

(esse não funciona em zsh , exceto na emulação sh / ksh).

Algumas outras notas:

  • join -t '\t' não funciona. Você precisaria de delim=$'\t' para armazenar uma TAB literal em $delim
  • Lembre-se de usar -- ao passar argumentos arbitrários para comandos (ou usar redirecionamentos sempre que possível). Então sort -- "$f1" ou melhor sort < "$f1" em vez de sort "$f1" .
  • As expansões aritméticas
  • também estão sujeitas a split + glob, portanto, também devem ser citadas ( shift "$((OPTIND - 1))" ) (mas isso não é um problema, pois você está usando bash que não herda $IFS do ambiente e você ' não está modificando IFS antes no script, mas ainda é uma boa prática).
por 24.07.2018 / 08:21