Tento problém souvisí s používáním funkce bash shell uvnitř AWK
Mám tento kód
#!/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
a mám tento soubor:
cat smile happy laugh
dog angry sad
mouse happy
wolf sad cry
fox sleep quiet
Výstup by měl vypadat takto:
smile
happy
laugh
angry
sad
happy
sad
cry
sleep
quiet
Problém, který mi říká bash: emotion: command not found
Podle komentáře akarilimana zde
toto nefunguje na mém Ubuntu 16.04. To je zvláštní, protože to dříve fungovalo „na Ubuntu 14.04.
Jak to tedy udělat v novějších verzích?
Přijatá odpověď:
To pravděpodobně není nejlepší způsob, jak k problému přistupovat.
Z awk
, vše, co můžete udělat, je vytvořit příkazový řádek, který system()
přechází na sh
. Takže potřebujete, aby byly argumenty formátovány v sh
syntaxe.
Takže budete potřebovat:
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)
}'
Zde cituji $1
awk takže jej lze bezpečně vložit do sh
příkazový řádek, který skončí spuštěním bash
s obsahem $1
jako poslední argument, který jej poté předá emotion
.
To předpokládá vaše sh
a vaše awk
neodstraňujte speciální proměnné prostředí, které bash
používá k exportu funkcí (jako pdksh
a deriváty (například mksh
) například nebo dash
od 0.5.8, což vysvětluje váš problém 14.04 vs 16.04), a že vaše distribuce nezakázala exportované funkce v bash
.
Pokud ano, můžete to udělat jako pro ksh
/zsh
a předejte definici funkce jiným způsobem, například:
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)
}'
V obou případech to znamená spustit jeden sh a jeden bash. Možná můžete předat $i
na bash
nějakým jiným způsobem než přes system()
který pokaždé provede dvě instance shellu. Jako:
awk '{for (i=2; i<=NF; i++) printf "%s\0" $i}' |
while IFS= read -r i; do
emotion "$i"
done
Nebo proveďte rozdělení slov v bash
přímo:
unset IFS
while read -ra fields; do
for i in "${fields[@]:1}"; do
emotion "$i"
done
done