bash函数包含循环和管道

时间:2014-05-01 15:06:29

标签: bash sed pipe user-defined-functions

我有一个bash脚本,它将文件的内容传递给一系列用户定义的函数,每个函数都对stdin执行sed操作,并将输出发送到stdout。

例如:

#!/bin/bash

MOD_config ()
{
  sed 's/config/XYZ/g'
}

MOD_ABC ()
{
  sed 's/ABC/WHOA!/g'
}

cat demo.txt \
 | MOD_config \
 | MOD_ABC

到目前为止一切顺利。一切都很好。

现在我想允许通过脚本命令行指定的其他模式更改对。例如,我想允许用户运行以下任何一个:

demo.sh                           # changes per script (MOD_config and MOD_ABC)
demo.sh CDE 345                   # change all 'CDE' to '345'
demo.sh CDE 345 AAAAA abababa     #  .. also changes 'AAAAA' to 'abababa'

所以我尝试将其添加到脚本中:

USER_MODS ()
{

  if [ $# -lt 1]; then

    #just echo stdin to stdout if no cmd line args exist
    grep .

  else

    STARTING_ARGC=$#
    I=1

    while [ $I -lt $STARTING_ARGC ]; then

      sed "s/$1/$2/g"

      shift
      shift
      I=`expr $I + 2`

    done

  fi

}

cat demo.txt \
  | MOD_config \
  | MOD_ABC \
  | USER_MODS

这种方法只有在我没有命令行args或者我只有两个时才有效。但是,在命令行中添加其他args无效。

不确定如何将while循环的一次迭代的stdout发送到下一次迭代的stdin。我认为这是我问题的症结所在。

有解决方法吗?或者我应该采取不同的方法吗?

3 个答案:

答案 0 :(得分:2)

要拥有动态管道列表,您需要一个递归解决方案。有一个函数应用一组修改,然后用两个较少的参数调用自己。如果函数没有参数,那么只需调用cat即可将stdin复制到stdout不变。

mod() {
    if (($# >= 2)); then
        search=$1
        replace=$2
        shift 2

        sed "s/$search/$replace/g" | mod "$@"
    else
        cat
    fi
}

# Apply two base modifications, plus any additional user mods ("$@")
mod config XYZ ABC 'WHOA!' "$@"

答案 1 :(得分:2)

注释:有超过2个参数,你的seds被执行,但是在第一个已经消耗了所有输入之后。相反,你想建立一系列sed命令。

#!/bin/bash

mod_config() { sed 's/config/XYZ/g'; }
mod_abc() { sed 's/ABC/WHOA!/g'; }

user_mods() {
  local IFS=';'
  local sed_subs=()
  while (($#>=2)); do
    sed_subs+=( "s/$1/$2/g" )
    shift 2
  done
  # at this point you have an array of sed s commands (maybe empty!).
  # Just join then with a semi colon using the IFS already set
  sed "${sed_subs[*]}"
}

cat demo.txt \
  | mod_config \
  | mod_abc \
  | user_mods "$@"   # <--- don't forget to pass the arguments to your function

并祈祷您的用户不会输入会混淆sed的内容,例如斜杠!

(抱歉,我把你所有的变量都降低了。大写的东西太丑了。)

答案 2 :(得分:1)

试试这个,使用递归调用来查看每次调用USER_MODS的替换对列表。

#!/bin/bash

MOD_config ()
{
  sed 's/config/XYZ/g'
}

MOD_ABC ()
{
  sed 's/ABC/WHOA!/g'
}

USER_MODS ()
{

  if [ $# -lt 1 ]; then

    #just echo stdin to stdout if no args exist
    grep .

  else

      # grap the next two arguments
      arg1=$1
      arg2=$2
      # remove them from the argument list
      shift
      shift
      # do the replacement for these two and recursivly pipe to the function with
      # the new argument list
      sed "s/$arg1/$arg2/g" | USER_MODS $@

  fi
}

cat demo.txt \
 | MOD_config \
 | MOD_ABC \
 | USER_MODS $@