【问题标题】:unix - shell script not executed in a proper order if executed in same time [closed]unix - 如果同时执行,则 shell 脚本未按正确顺序执行 [关闭]
【发布时间】:2015-02-10 17:00:46
【问题描述】:

我在 AIX 7.1 中编写了 shell 脚本,但它没有按正确的顺序执行。

shell脚本是

receive 2 parameter $param and $filename

listoffiles='ls ${param}/*.txt'
awk 'FNR-1' ${listoffiles} >> ${param}/${filename}
mv ${param}/*.txt ${param}/archive

我的目标是将${listoffiles} 中的行合并到一个文件中,不包括每个文件的标题。 之后,我想将 ${listoffiles} 文件,包括生成的 ${param}/${filename} 移动到一个文件夹(假设它是“存档”文件夹)。 ${filename} 应该引用参数,并为每次执行调用提供唯一的文件名,并且始终具有“.txt”扩展名。

问题是:如果同时有3个(或更多)脚本执行,结果会是:

  1. 一次执行将产生正确的顺序

  2. 其他执行会导致mv ${param}/*.txt ${param}/archiveawk 'FNR-1' ${listoffiles} >> ${param}/${filename}之前先执行

我在这里做错了什么?或者有什么方法可以保证脚本严格执行它的步骤? (我尝试添加&&; 但结果保持不变)

【问题讨论】:

  • Shell 脚本在使用空格时需要非常精确。赋值必须在等号两边都没有空格。这意味着awk 脚本没有文件要处理。学习使用bash -x(和/或sh -x)进行调试。即使您修复了这个问题,当它来自扩展 ${listoffiles} 时,shell 也不会扩展或 glob $param/*.txt
  • @JonathanLeffler, ...它不会进行扩展,可以肯定的是,但它为什么不进行 glob(如果引用样式已更正以便可以执行扩展) ?这根本不是说我在为该代码辩护。将 glob 表达式存储在标量变量中当然是可恶的。
  • @CharlesDuffy:哦——你是对的。如果 cmets 可以编辑更长时间,我会修复它。如果$param$listoffiles 之外处理(例如listoffiles='*.txt'; echo "$param"/$listoffiles),则会发生通配。如果您有一个名为$param 的目录(而不是$param 的扩展),则会发生通配。基本上,您必须认真考虑 shell 处理expansions 的方式。
  • @Kioels,这也不是好的做法。见mywiki.wooledge.org/ParsingLs
  • 您描述的症状是完全如果param 在多个解释之间是相同的,那么人们会期望什么,如果不是,则完全无法解释。 (并不是任何给定的实例都在乱序运行命令,而是实例 A 正在重命名文件,而实例 B 正在创建它们)。

标签: linux bash shell awk aix


【解决方案1】:

不要硬编码诸如combine.txt 之类的名称;相反,请使用 mktemp 为您的实例创建一个唯一的临时文件:

tempfile=$(mktemp "$param/combine.XXXXXX")
awk 'FNR-1' "$param"/*.txt >"$tempfile"
mv "$tempfile" "$param/archive"

使用唯一的文件名将允许脚本的并发实例在不相互交互的情况下运行。

【讨论】:

  • 抱歉,我已经编辑了问题。应该有另一个参数给出文件名。文件名将始终具有“.txt”扩展名。
  • 如果param 是一个目录,并且您有两个并发进程正在修改该目录,那么解决方案怎么可能可能允许并发操作?当然,您的*.txt 不会与当前 shell 创建或编辑的内容隔离开来。
  • 如果你想要的可能的,你需要更好地解释它,这样我才能理解它是如何或为什么可能的。
  • $param 每次执行都应该是唯一的。假设第一个进程$param引用'/dat/firstfolder',第二个进程$param引用'/dat/secondfolder',问题是为什么第二个进程不会按顺序执行脚本。
  • 啊。有了这个澄清,答案很简单:编写的脚本确实总是按顺序运行。因此,您的问题是基于误诊;实际问题在其他地方。您是否遵循了 Jonathan 给您的建议并使用 bash -x 重现了该问题?
【解决方案2】:

由于您首先收集文件列表,然后对其进行处理,因此当它开始对其进行处理时,该文件可能已被另一个进程移动。

您可能想尝试锁定文件 - 请参阅 How to prevent a script from running simultaneously? - 指定与您要处理的文件相关的文件名,并给它一个短暂的超时时间。如果另一个进程做了同样的事情,它将失败。你可以跳过这个,因为另一个线程正在处理它。

还要确保(正如@Charles Duffy 正确指出的那样)每个进程都写入不同的文件。

【讨论】:

  • 在我的例子中,脚本的执行总是需要一个唯一的 $param 每次执行。锁定文件应该没有问题,因为每个进程都是唯一的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多