bash脚本有时会“跳过”语句的前两个字符。如何解决?

问题描述 投票:2回答:1

我编写了一个bash脚本,该脚本运行从远程登台数据库到本地计算机(我的Macbook)上的开发数据库的部分同步。该脚本首先将某些表从登台db(通常通过SSH隧道)转储到本地.sql文件,然后针对本地db执行这些.sql文件。这是脚本(一些表已重命名以保护罪恶感):

rm -rf export/
mkdir export

set -e # abort if any command in the script fails

abort() {
  echo $1
  exit 1
}

dump_table() {
  echo "Dumping to $1.sql..."
  pg_dump $DATABASE_URL -t $1 --data-only > export/$1.sql
}

[ -z "$DATABASE_URL" ] && abort "usage: DATABASE_URL=postgres://un:pw@localhost:55555/dbname sh bin/importdb.sh"

echo "_structure.sql..."
pg_dump $DATABASE_URL -s > export/_structure.sql

dump_table events
dump_table users
dump_table attendees
dump_table orders
dump_table admissions
dump_table teams
# etc...

echo ""
echo "Done with dump from staging!"
echo "Starting local import..."

# Prepend all dumpfiles with the ON_ERROR_STOP flag so the script will abort on error
for f in export/*.sql; do ex -sc '1i|\set ON_ERROR_STOP on' -cx $f; done

dropdb cello_development
createdb cello_development
psql -d cello_development -f export/_structure.sql

# Because we're only importing certain tables, we first need to remove
# a bunch of FKs so that references to un-imported tables are ignored.
psql -d cello_development -c "ALTER TABLE users DROP CONSTRAINT fk_rails_047fa7c340"
psql -d cello_development -c "ALTER TABLE users DROP CONSTRAINT fk_rails_752aed9fe5"
psql -d cello_development -c "ALTER TABLE events DROP CONSTRAINT fk_rails_e1c8c23245"
psql -d cello_development -c "ALTER TABLE events DROP CONSTRAINT fk_rails_1a56b1500c"
psql -d cello_development -c "ALTER TABLE events DROP CONSTRAINT fk_rails_ae012fe18a"
psql -d cello_development -c "ALTER TABLE events DROP CONSTRAINT fk_rails_95c0269b21"
# etc...

echo "events..."
psql -d cello_development -f export/events.sql
echo "users..."
psql -d cello_development -f export/users.sql
echo "attendees..."
psql -d cello_development -f export/attendees.sql
echo "orders..."
psql -d cello_development -f export/orders.sql
echo "admissions..."
psql -d cello_development -f export/admissions.sql
echo "teams..."
psql -d cello_development -f export/teams.sql
# etc...

echo ""
echo "Done with local db import!"

我首先打开ssh隧道以允许我访问远程(源)数据库,然后运行带有DATABASE_URL env var设置的脚本来运行此脚本。如您所见,我调用脚本的方式没有什么花哨的:

# In one window, open an SSH tunnel so I can access the source db
ssh -NTL 55555:cello-staging.rds.amazonaws.com:5432 [email protected]

# In second window, run the script with DATABASE_URL set
DATABASE_URL=postgres://un:pw@localhost:55555/cello_staging sh bin/importdb.sh

其中一些表很大(4m +行),因此整个脚本可能需要几个小时才能完成。 (是的,我确定有更好的方法来植入开发数据库。)

我的问题是:该脚本经常(约60%的时间)失败,并出现错误,提示部分语句被“跳过”。一个例子:

# The failure message:
-bash: mp_table: command not found

# The statement at that line in the script:
dump_table admissions

另一个例子:

# The failure message:
bin/importdb.sh: line 65: port/admissions.sql: No such file or directory

# The statement at that line in the script:
psql -d cello_development -f export/admissions.sql

失败与我在该行上运行该语句所看到的一致,前两个字符(总是正好两个前导字符)。例如,如果我独立运行语句dump_table admissions(假设已定义dump_table函数),则我希望它能够成功;但是,如果我独立运行语句mp_table admissions,则会看到与上述相同的失败消息。

[失败往往是在执行几个特别大的表操作后立即发生的。但是,并非所有比较大的表都受到相同的影响。

我的最佳猜测是,某种程度上,昂贵的postgres DB操作正在运行,导致bash脚本变得混乱,有时在随后的语句中“跳过”字符。

我的问题:

  • 您将如何解决此问题? bash脚本中的一条语句在执行之前(有时)被更改/缩短了吗?
  • 执行bash脚本时,早期语句的副作用是否可能以某种方式影响脚本中后续语句的措辞?
  • 我正在运行的psqlpg_dump命令是否可能与正在调用它们的脚本内容进行交互?

上下文:我正在使用iTerm2在MacOS 10.14上。本地数据库服务器是Postgres v9.6。

编辑1:脚本本身绝不会被修改。它已签入Git,未显示任何更改,它在我的本地计算机上,除我以外,没有用户有权对文件进行更改。

Edit 2:重写为包括正在运行的完整脚本以及我用来调用它的完整命令。

bash
1个回答
0
投票

我不知道会发生什么,但是有一些关于故障排除/避免的建议。

  • 在我看来,这真的像是从外壳窃取输入内容。出现问题之前,请尝试重定向命令的输入:

    pg_dump $DATABASE_URL -s > export/_structure.sql </dev/null
    
    dump_table events </dev/null
    dump_table users </dev/null
    ...etc
    

    如果无法阻止,请尝试删除某些重定向,直到缩小了引起问题的命令的范围。或者,您也可以将它们全部留在这里...

    如果没有阻止它发生,那么我比现在要更加神秘。

  • 您还可以尝试将整个脚本(shebang行除外)包装在某种形式的shell块中,并在末尾显式退出-类似于if true; then ... exit; fi甚至只是{ ... exit; }。这将强制外壳程序在执行任何块之前读取并解析整个块(并在尝试执行其后的任何内容之前退出并退出),因此,如果文件或文件描述符发生任何混乱或无关紧要的话:

    #!/bin/bash
    if true; then    # Workaround to avoid script reading weirdness
        rm -rf export/
        mkdir export
    
        ...
    
        exit
    fi
    

顺便说一句,我建议在脚本的开头使用适当的shebang行,使其可执行(chmod +x bin/importdb.sh),然后直接运行而无需使用sh命令。本质上,脚本的作者(通过脚本本身)应定义脚本编写的语言/方言/等,而不是运行脚本的人(/外部脚本/ cron入口/以任何方式)。

© www.soinside.com 2019 - 2024. All rights reserved.