如何在 awk 内的 bash 脚本中调用 bash 函数?

如何在 awk 内的 bash 脚本中调用 bash 函数?

这个问题涉及到在 AWK 中使用 bash shell 函数

我有这个代码

#!/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

我有这个文件:

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

输出应该是这样的:

smile
happy
laugh
angry
sad
happy    
sad
cry
sleep
quiet 

它告诉我的问题bash: emotion: command not found

根据 akarilimano 的评论这里

这在我的 Ubuntu 16.04 上不起作用。这很奇怪,因为它曾经在“Ubuntu 14.04 上运行”。

那么在新版本中如何做到这一点呢?

答案1

这可能不是解决问题的最佳方法。

awk,您所能做的就是构建一个system()传递到 的命令行sh。因此,您需要在语法中格式化参数sh

所以你需要:

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)
  }'

这里引用 awk,$1这样它就可以安全地嵌入到sh命令行中,最终bash以最后一个参数的内容运行$1,然后将其传递给emotion.

假设您sh和您awk不删除bash用于导出函数的特殊环境变量(例如pdksh和 衍生物(例如mksh)),dash从 0.5.8 开始,这解释了您的 14.04 与 16.04 问题),并且您的发行版尚未禁用bash.

如果是这样,您可以像 for ksh/一样执行此操作zsh,并以其他方式传递函数的定义,例如:

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)
  }'

在这两种情况下,这都意味着为其运行一个 sh 和一个 bash。也许您可以将 a 传递$ibash其他方式,而不是通过 asystem()每次执行 shell 的两个实例。喜欢:

awk '{for (i=2; i<=NF; i++) printf "%s\0" $i}' |
  while IFS= read -r i; do
    emotion "$i"
  done

或者直接进行分词bash

unset IFS
while read -ra fields; do
  for i in "${fields[@]:1}"; do
    emotion "$i"
  done
done

答案2

您的脚本在 Ubuntu 16.04 上不起作用,因为/bin/sh它链接到dashshell,而在 Ubuntu 14.04 上则/bin/sh链接到bashshell。为什么这很重要? Awk 的system()函数使用/bin/sh并因此调用dashUbuntu 16.04 上的 shell。

相关内容