Este problema está relacionado con el uso de la función bash shell dentro de AWK
Tengo este 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
y tengo este archivo:
cat smile happy laugh
dog angry sad
mouse happy
wolf sad cry
fox sleep quiet
La salida debería ser así:
smile
happy
laugh
angry
sad
happy
sad
cry
sleep
quiet
El problema me dice bash: emotion: command not found
Según el comentario de akarilimano aquí
esto no funciona en mi Ubuntu 16.04. Esto es extraño, porque solía funcionar “en Ubuntu 14.04.
Entonces, ¿cómo hacerlo en las versiones más nuevas?
Respuesta aceptada:
Probablemente esa no sea la mejor manera de abordar el problema.
Desde awk
, todo lo que puede hacer es construir una línea de comando que system()
pasa a sh
. Entonces, necesita que los argumentos estén formateados en el sh
sintaxis.
Así que necesitarías:
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 \"[email protected]\"'\'' bash " sh_quote($1)
}'
Aquí citando $1
de awk para que se pueda incrustar de forma segura en el sh
línea de comando que termina ejecutando bash
con el contenido de $1
como último argumento, que luego lo pasa a emotion
.
Eso asume su sh
y tu awk
no elimine las variables de entorno especiales que bash
utiliza para exportar funciones (como pdksh
y derivados (como mksh
) hacer por ejemplo, o dash
desde 0.5.8, lo que explica su problema de 14.04 frente a 16.04), y que su distribución no ha deshabilitado las funciones exportadas en bash
.
Si es así, podrías hacerlo como para ksh
/zsh
y pasar la definición de la función de otra 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 \"[email protected]\"'\'' bash " \
sh_quote($1)
}'
En ambos casos, eso significa ejecutar un sh y un bash para ello. Tal vez puedas pasar el $i
a bash
de otra manera que no sea a través de un system()
que ejecuta dos instancias de un shell cada vez. Me gusta:
awk '{for (i=2; i<=NF; i++) printf "%s\0" $i}' |
while IFS= read -r i; do
emotion "$i"
done
O haz la división de palabras en bash
directamente:
unset IFS
while read -ra fields; do
for i in "${fields[@]:1}"; do
emotion "$i"
done
done