Como posso chamar uma função bash no script bash do awk?

4

Esse problema está relacionado a Usando a função bash shell dentro do AWK

Eu tenho esse código

#!/bin/bash

function emotion() {
            #here is function code end with return value...
            echo $1
}

export -f emotion

#I've put all animals in array
animalList=($(awk '{print $1}' animal.csv)) 

#loop  array and grep all the lines form the file
for j in ${animalList[@]}
do
  :                                                     #here I'am running a bash script calling emotion function 
   grep $j animal.csv | awk '{for(i=2;i<=NF;i++){system("bash -c '\''emotion "$i"'\''")}}'
done

e eu tenho este arquivo:

cat    smile    happy   laugh
dog    angry    sad
mouse  happy    
wolf   sad      cry
fox    sleep    quiet 

A saída deve ser assim:

smile
happy
laugh
angry
sad
happy    
sad
cry
sleep
quiet 

O problema me diz bash: emotion: command not found

De acordo com o comentário de akarilimano aqui

this is not working on my Ubuntu 16.04. This is strange, because it used to work "on Ubuntu 14.04.

Então, como fazer isso em versões mais recentes?

    
por krankry 26.10.2017 / 10:19

2 respostas

3

Essa provavelmente não é a melhor maneira de abordar o problema.

A partir de awk , tudo o que você pode fazer é criar uma linha de comando que system() passe para sh . Então, você precisa dos argumentos para serem formatados na sintaxe sh .

Então você precisaria:

emotion() {
  echo "$i"
}
export -f emotion
awk -v q="'" '
  function sh_quote(s) {
    gsub(q, q "\" q q, s)
    return q s q
  }
  {
    for (i = 2; i <= NF; i++)
      status = system("bash -c '\''emotion \"$@\"'\'' bash " sh_quote($1)
  }'

Aqui citando o $1 de awk para que possa ser incorporado com segurança na linha de comando sh que acaba executando bash com o conteúdo de $1 como último argumento, que passa para emotion . / p>

Isso pressupõe que sh e awk não tirem as variáveis de ambiente especiais que bash usa para exportar funções (como pdksh e derivadas (como mksh ), por exemplo, ou dash desde 0.5.8, o que explica seu problema 14.04 vs 16.04 , e que sua distribuição não desativou funções exportadas em bash .

Em caso afirmativo, você pode fazer como ksh / zsh e passar a definição da função de outra forma, como:

CODE=$(typeset -f emotion) awk -v q="'" '
  function sh_quote(s) {
    gsub(q, q "\" q q, s)
    return q s q
  }
  {
    for (i = 2; i <= NF; i++)
      status = system("bash -c '\''eval \"$CODE\"; emotion \"$@\"'\'' bash " \
                      sh_quote($1)
  }'

Em ambos os casos, isso significa executar um sh e um bash para ele. Talvez você possa passar o $i para bash de alguma outra forma que não seja através de um system() que executa duas instâncias de um shell a cada vez. Como:

awk '{for (i=2; i<=NF; i++) printf "%s
unset IFS
while read -ra fields; do
  for i in "${fields[@]:1}"; do
    emotion "$i"
  done
done
" $i}' | while IFS= read -r i; do emotion "$i" done

Ou faça a divisão da palavra em bash diretamente:

emotion() {
  echo "$i"
}
export -f emotion
awk -v q="'" '
  function sh_quote(s) {
    gsub(q, q "\" q q, s)
    return q s q
  }
  {
    for (i = 2; i <= NF; i++)
      status = system("bash -c '\''emotion \"$@\"'\'' bash " sh_quote($1)
  }'
    
por 26.10.2017 / 11:04
0

Seu script não funciona no Ubuntu 16.04 porque /bin/sh está vinculado ao dash shell, enquanto no Ubuntu 14.04 /bin/sh está vinculado ao bash shell. Por que isso importa? A função system() do awk usa /bin/sh e, portanto, invoca o shell dash no Ubuntu 16.04.

    
por 26.10.2017 / 12:43