【问题标题】:How to run shell script commands in an sh file in parallel?如何在 sh 文件中并行运行 shell 脚本命令?
【发布时间】:2020-03-16 12:41:59
【问题描述】:

我正在尝试备份我的数据库服务器中的表。

我有大约 200 张桌子。我有一个 shell 脚本,其中包含用于备份每个表的命令,例如:

backup.sh

psql -u username ..... table1 ... file1;
psql -u username ..... table2 ... file2;
psql -u username ..... table3 ... file3;

我可以在我的机器上运行脚本并创建备份。但是由于有 200 个表,它将按顺序运行命令并且需要大量时间。 我想并行运行备份命令。我看过他们建议在每个命令后使用 && 或使用nohup 命令或wait 命令的文章。

但我不想编辑脚本并包含大约 200 个这样的命令。

有什么方法可以并行运行这些 shell 脚本命令列表?像nodejs 这样的东西吗?有可能做到吗?还是我看错了?

脚本中的示例命令:

psql --host=somehost --port=5490 --username=user --dbname=db -c '\copy dbo.tablename TO "/home/username/Desktop/PostgresFiles/tablename.csv" with DELIMITER ","';

【问题讨论】:

  • 可能数据库已经在尽可能快地为您提供 tae 表,而试图让它同时做更多事情只会产生拥塞。
  • 我的 shell 命令正在使用 \copy 这是一个客户端 CSV 创建,当我正常运行脚本时它工作正常。但是如果我使用上面提到的方法,它正在考虑 \copy as COPY 这是 db 用户无权访问的服务器端副本。
  • @tripleee 用脚本中的示例命令更新了问题。
  • 这不应该发生,除非有你没有显示的事情发生,例如将命令传递给远程 shell。
  • 我尝试了 drldcsta 在以下答案中提到的命令

标签: linux shell ubuntu parallel-processing debian


【解决方案1】:

您可以利用 xargs 并行运行命令,并控制并发作业的数量。运行 200 个备份作业可能会使您的数据库不堪重负,并导致性能不佳。

假设您有 backup.sh,每行有一个备份命令

xargs -P5 -I{} bash -c "{}" < backup.sh

应修改backup.sh 中的命令以允许引用(尽可能使用单引号,转义双引号):

psql --host=somehost --port=5490 --username=user --dbname=db -c '\copy dbo.tablename TO \"/home/username/Desktop/PostgresFiles/tablename.csv\" with DELIMITER \",\"';

其中 -P5 控制并发作业的数量。这将能够处理没有双引号的命令行。对于上述脚本,您将"\copy ..." 更改为'\copy ...'

更简单的替代方法是使用帮助器backup-table.sh,它将采用两个参数(表、文件)并使用

xargs -P5 -I{} backup-table.sh "{}" < tables.txt

并将所有复杂的引用放入backup-table.sh

【讨论】:

  • 我收到psql: warning: extra command-line argument 脚​​本中所有单词的错误。
  • 糟糕,我没有意识到完整的命令有双引号。我已经发布了小更新 - 但根据答案,它需要将 backup.sh 中的双引号更改为单引号。希望它能给你带来更多的里程。
  • 即使将" 替换为' 并将' 替换为",也会出现同样的问题。
  • 你能分享来自 backup.txt 的示例行(更改后)吗?
  • 已在问题中更新。顺便说一句,我正在使用 Ubuntu。我想它不应该引起问题。
【解决方案2】:
doit() {
  table=$1
  psql --host=somehost --port=5490 --username=user --dbname=db -c '\copy dbo.'$table' TO "/home/username/Desktop/PostgresFiles/'$table'.csv" with DELIMITER ","';
}
export -f doit

sql --listtables -n postgresql://user:pass@host:5490/db | parallel -j0 doit

【讨论】:

    【解决方案3】:

    脚本中除了单个命令之外还有其他逻辑吗? (例如:和if's 或输出处理?)。

    如果它只是一个包含脚本列表的文件,您可以为脚本编写一个包装器(或来自 CLI 的循环)EG:

    $ cat help.txt
    echo 1
    echo 2
    echo 3
    
    $ while read -r i;do bash -c "$i" &done < help.txt
    [1] 18772
    [2] 18773
    [3] 18774
    1
    2
    3
    [1]   Done                    bash -c "$i"
    [2]-  Done                    bash -c "$i"
    [3]+  Done                    bash -c "$i"
    
    $ while read -r i;do bash -c "$i" &done < help.txt
    [1] 18820
    [2] 18821
    [3] 18822
    2
    3
    1
    [1]   Done                    bash -c "$i"
    [2]-  Done                    bash -c "$i"
    [3]+  Done                    bash -c "$i"
    

    help.txt 的每一行都包含一个命令,我运行一个循环,在其中获取每个命令并在 subshel​​l 中运行它。 (这是一个简单的示例,我只是为每个作业设置背景。您可以使用 xargs -pparallel 之类的东西变得更复杂,但这是一个起点)

    【讨论】:

    • 我的 shell 命令正在使用 \copy,这是一个客户端 CSV 创建,当我正常运行脚本时它工作正常。但是如果我使用上述方法,它会将\copy 视为COPY,这是db 用户无权访问的服务器端副本。
    • 您需要使用read -r 才能使read 不破坏反斜杠。除非您特别需要原始 sh 的古怪传统行为,否则您实际上基本上总是希望 -r 选项与 read 一起使用。
    猜你喜欢
    • 2012-07-27
    • 2018-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-07
    • 1970-01-01
    • 2017-01-16
    • 1970-01-01
    相关资源
    最近更新 更多