【问题标题】:Shell script - awk extract block from file into arrayShell 脚本 - awk 从文件中提取块到数组中
【发布时间】:2014-01-27 10:33:34
【问题描述】:

我目前正在编写一个读取 Vagrantfile 并引导它的 shell 脚本(简而言之;))

但是我用下面的代码碰壁了:

TEST=()
while read result; do
  TEST+=(`echo ${result}`)
done <<< `awk '/config.vm.define[ \s]\"[a-z]*\"[ \s]do[ \s]\|[a-zA-Z_]*\|/, /end/ { print }' Vagrantfile`

echo "${TEST[1]}"

当我将 Vagrantfile 传递到这个 awk 模式正则表达式中时,其中定义了两台机器(config.vm.define),它们被找到了。

输出

config.vm.define "web" do |web|

web.vm.box       = "CentOs"
web.vm.box_url   = "http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.4-x86_64-v20130731.box"
web.vm.hostname  = 'dev.local'

web.vm.network :forwarded_port, guest: 90, host: 9090
web.vm.network :private_network, ip: "22.22.22.11"

web.vm.provision :puppet do |puppet|
  puppet.manifests_path = "puppet/manifests"
  puppet.manifest_file  = "web.pp"
  puppet.module_path    = "puppet/modules"
  puppet.options        = ["--verbose", "--hiera_config /vagrant/hiera.yaml", "--parser future"]
end
config.vm.define "db" do |db_mysql|

db_mysql.vm.box       = "CentOs"
db_mysql.vm.box_url   = "http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.4-x86_64-v20130731.box"
db_mysql.vm.hostname  = 'db.mysql.local'

db_mysql.vm.network :private_network, ip: "22.22.22.22"
db_mysql.vm.network :forwarded_port, guest: 3306, host: 3306

db_mysql.vm.provision :puppet do |puppet|
  puppet.manifests_path = "puppet/manifests"
  puppet.manifest_file = "db.pp"
  puppet.module_path = "puppet/modules"
  puppet.options = ["--verbose", "--hiera_config /vagrant/hiera.yaml", "--parser future"]
end

但我似乎无法很好地将它们传递到数组中。我想要的是 TEST 数组包含两个索引,机器 config.vm.define 块作为它们的对应值。

例如

TEST[0] = 'config.vm.define "web" do |web|

.... [REST OF THE BLOCK CONTENT] ...

end'

TEST[1] = 'config.vm.define "db" do |db_mysql|

.... [REST OF THE BLOCK CONTENT] ...

end'

输出echo "${TEST[1]}"nothingecho "${TEST[0]}" 返回如上图所示的整个块。

我玩过 IFS / RS / FS,但我似乎无法获得我想要的输出。

【问题讨论】:

  • awk 命令本身的确切输出是什么?在您的示例中echo "${TEST[1]}" 的结果是什么?
  • 每个config.vm.define 块中是否有换行符?
  • @grebneke 用输出更新了问题,是的,里面有换行符

标签: arrays bash shell awk vagrant


【解决方案1】:

一种解决方案可能是将这两个块写入两个单独的文件(blk1blk2),如下所示:

awk '
  /config.vm.define[[:space:]]\"[a-z]*\"[[:space:]]do[[:space:]]\|[a-zA-Z_]*\|/{f=1; i++}
  f{print $0 > "blk"i}
  /end/ {f=0}' Vagrantfile

然后稍后将这两个文件读入bash数组中

IFS= TEST=( $(cat <"blk1") $(cat <"blk2") )

注意:

  • 正则表达式 \s 似乎仅适用于最新版本的 gawk(适用于 4.1 版,但不适用于 3.1.8 版。
  • 对于gawk 3.1.8 版,请改用[[:space:]]
  • 对于gawk 4.1 版,正则表达式\s 在括号[\s] 内不起作用。使用config.vm.define[[:space:]]config.vm.define\s..

更新

另一种方法是在块之间插入人工分隔符,例如字符串@@@。那你就可以了

IFS= TEST=()
while IFS= read -r -d '@' line ; do
    TEST+=($line)
done < <(awk '
  /config.vm.define[[:space:]]\"[a-z]*\"[[:space:]]do[[:space:]]\|[a-zA-Z_]*\|/{f=1; i++}
  f{print }
  /end/ {f=0; print "@@@"}' Vagrantfile) 

【讨论】:

  • 谢谢,我会试一试。我会告诉你的!
  • 试一试,效果很好。您的第一个解决方案中的小错误。我需要将变量文件名括在括号中。否则它给出了一个错误。这样它就可以正确连接awk '/config.vm.define[[:space:]]\"[a-z]*\"[[:space:]]do[[:space:]]\|[a-zA-Z_]*\|/ {f=1; i++} f{print $0 &gt; ("block"i)} /end/ {f=0}' Vagrantfile
  • 太棒了!感谢您的评论:)
猜你喜欢
  • 2010-11-29
  • 2015-08-16
  • 1970-01-01
  • 2018-06-14
  • 1970-01-01
  • 1970-01-01
  • 2011-09-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多