bash 脚本有时会"skips"语句的前两个字符。如何排除故障?



我写了一个bash脚本,它运行从远程暂存数据库到本地机器(我的Macbook(上的开发数据库的部分同步。该脚本首先将某些表从暂存数据库(通常通过SSH隧道(转储到本地.sql文件,然后针对本地数据库执行这些.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_URLenv-var集运行该脚本。正如你所看到的,我调用脚本的方式并没有什么特别之处:

# In one window, open an SSH tunnel so I can access the source db
ssh -NTL 55555:cello-staging.rds.amazonaws.com:5432 ubuntu@staging.cello.com
# 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脚本时,早期语句的副作用是否可能以某种方式影响脚本中后续语句的措辞
  • 是否可能CCD_ 5&我正在运行的pg_dump命令是否与调用它们的脚本内容交互

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

编辑1:脚本本身在任何时候都不会被修改。它已被签入Git,没有任何更改显示,它在我的本地机器上,除了我之外,任何用户都不应该有权对文件进行更改。

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

我不明白是什么导致了这种情况,但有几个关于故障排除/避免的建议。

  • 在我看来,这真的像是有什么东西在窃取shell的输入。尝试在问题发生之前重定向命令的输入:

    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; }。这将迫使shell在执行任何一个块之前读取和解析整个块(并在尝试执行之后的任何内容之前退出(,因此,如果文件或文件描述符出现任何问题,或者其他什么都无关紧要:

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

BTW,我确实建议在脚本的开头使用适当的shebang行,使其可执行(chmod +x bin/importdb.sh(,然后直接运行,不使用sh命令。从本质上讲,脚本的作者(通过脚本本身(应该定义脚本所用的语言/方言等,而不是运行脚本的人(/exter script/cron entry/whatevery(。

最新更新