在 crontab 上创建一个流编辑器命令,并每 15 分钟重写一个文件
Create a command on crontab that stream editor and rewrite a file every 15 minutes
假设我有一个文件,其模式与另一个文件相匹配:
file_names.txt
pfg022G
pfg022T
pfg068T
pfg130T
pfg181G
pfg181T
pfg424G
pfg424T
我想使用 file_names.txt
并使用 sed
命令进入 example.conf
:
example.conf
{
"ExomeGermlineSingleSample.sample_and_unmapped_bams": {
"flowcell_unmapped_bams": ["/groups/cgsd/alexandre/gatk-workflows/src/ubam/pfg022G.unmapped.bam"],
"unmapped_bam_suffix": ".unmapped.bam",
"sample_name": "pfg022G",
"base_file_name": "pfg022G.GRCh38DH.target",
"final_gvcf_base_name": "pfg022G.GRCh38DH.target"
},
sed 命令会将 example.conf
上的 pfg022G
替换为 pfg022T
,这是 file_names.txt
(sed s/pfg022G/pfg022T/
) 中的下一项。此时的 example.conf
应该是这样的:
{
"ExomeGermlineSingleSample.sample_and_unmapped_bams": {
"flowcell_unmapped_bams": ["/groups/cgsd/alexandre/gatk-workflows/src/ubam/pfg022T.unmapped.bam"],
"unmapped_bam_suffix": ".unmapped.bam",
"sample_name": "pfg022T",
"base_file_name": "pfg022T.GRCh38DH.target",
"final_gvcf_base_name": "pfg022T.GRCh38DH.target"
},
15 分钟后替换应该是 pfg022T
到 pfg068T
等等,直到 file_names.txt
中的所有项目都用完。
与周期性的 cron 作业相比,创建 daemon/background 进程可能更容易。
while read str;
do
sleep 900;
sed -ri "s@(^\"flowcell_unmapped_bams.*gatk-workflows/src/ubam/)(.*)(\.unmapped\.bam\"\],.*$)@$str@;s/(^\"sample.name.*: \")(.*)(\",.*$)/$str/;s/(^\"base_file_name.*: \")(.*)(\.GRCh38DH.*$)/$str/" example.conf;
done < file_names.txt &
通过while循环逐行读取file_names.txt的内容,将行读取为变量str。休眠 900 秒,然后在三个 sed 命令中使用这个 str 变量。在所有命令中,使用 -r 或 -E 启用正则表达式解释并将行分成三部分。替换第 1 部分的行,然后是变量 str 和第 3 部分。在末尾添加 & 到 运行 进程到后台。
对于我认为这将如何工作的逻辑,
- 创建一个 cronjob,或者如果您的服务器定期关闭,则创建一个 anacron 作业,每 15 分钟 运行 一个 bash 脚本。
- 在 bash 脚本中,您可以使用
if
语句,您可以使用 grep
测试 filenames.txt
中的每一行,哪一行存在于 example.conf 中, 如果该行存在则转到 filenames.txt
中的下一行。如果您在 file_names.txt
中的最后一个字符串处,那么 bash 脚本应该停止 运行 exit
命令
- 您将 运行 sed 命令替换您的字符串。我确实认为
replace
命令应该能够取代它。
- 如果您必须重新加载服务以加载修改后的配置,然后再添加此配置。
以下 crontab 会 运行 您的脚本每 15 分钟:
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7)
# | | | | |
# * * * * * command to be executed
15 * * * * /path/to/script
有script
阅读
#!/usr/bin/env sh
file1="file_names.txt"
file2="example.conf"
sed -i -e "$(awk '(NR>1){print "s/"p"/""/g"}{p=}' $file1 | tac)" example.conf
我们在这里使用的技巧是进行敬畏替换。文件 example.conf
始终只包含一个也在“file_names.txt”中的字符串。因此,如果您尝试从最后一个替换到前面,您只会进行一次替换。
我们在这里使用 awk
来构建一个 sed
-脚本,并使用 tac
来反转它,这样我们只有一个匹配项:
$ awk '(NR>1){print "s/"p"/""/g"}{p=}' $file_names.txt
s/pfg022G/pfg022T/g
s/pfg022T/pfg068T/g
s/pfg068T/pfg130T/g
s/pfg130T/pfg181G/g
s/pfg181G/pfg181T/g
s/pfg181T/pfg424G/g
s/pfg424G/pfg424T/g
如果我们用上面的脚本做一个sed
,我们总是会以pfg424T
(最后一个条目)结束,因为它会找到一个匹配项(假设我们在第三个条目中pfg068T
),因此 sed 将在此之后执行所有替换。但是,当我们颠倒顺序时(使用 tac
),sed
只会找到一个匹配项。
我可能会提前在队列目录中生成所有文件,并让 cron
作业在每次调用时选择下一个文件。
awk 'NR==FNR { a[++n] = [=10=]; next }
{ file = ".conf"
for(i=1; i<=n; i++) {
l = a[i]; sub("{{name}}", [=10=], l);
print l >file }
close file
}' - file_names.txt <<\____
{
"ExomeGermlineSingleSample.sample_and_unmapped_bams": {
"flowcell_unmapped_bams": ["/groups/cgsd/alexandre/gatk-workflows/src/ubam/{{name}}.unmapped.bam"],
"unmapped_bam_suffix": ".unmapped.bam",
"sample_name": "{{name}}",
"base_file_name": "{{name}}.GRCh38DH.target",
"final_gvcf_base_name": "{{name}}.GRCh38DH.target"
},
____
运行 在您的示例中 file_names.txt
创建以下文件:
pfg022G.conf pfg068T.conf pfg181G.conf pfg424G.conf
pfg022T.conf pfg130T.conf pfg181T.conf pfg424T.conf
内容如您所愿;这是 pfg0222G.conf
:
{
"ExomeGermlineSingleSample.sample_and_unmapped_bams": {
"flowcell_unmapped_bams": ["/groups/cgsd/alexandre/gatk-workflows/src/ubam/pfg022G.unmapped.bam"],
"unmapped_bam_suffix": ".unmapped.bam",
"sample_name": "pfg022G",
"base_file_name": "pfg022G.GRCh38DH.target",
"final_gvcf_base_name": "pfg022G.GRCh38DH.target"
},
现在,您的 cron
作业只需要将其中一个移动到 example.conf
并进行处理。当包含文件的目录为空时,您就完成了。
#!/bin/sh
for f in confdir/*.conf; do
if [ -e "$f" ]; then
# Safeguard against clobbering previous run
if [ -e ./example.conf ]; then
echo "[=13=]: example.conf is still there -- skipping this run" >&2
exit 63
fi
mv "$f" ./example.conf
exec your_main_script_or_whatever
# Should never fall through to here, but whatever
break
else
echo "[=13=]: directory empty -- aborting" >&2
fi
done
为了避免竞争条件——如果之前的 cron
作业仍然是 运行,或者由于某种原因失败了,我们不想破坏它的输入文件。这需要 your_main_script_or_whatever
在完成时删除 example.conf
。如果你不关心这个,也许你可以简单地从上面的脚本中删除保护条件。
假设我有一个文件,其模式与另一个文件相匹配:
file_names.txt
pfg022G
pfg022T
pfg068T
pfg130T
pfg181G
pfg181T
pfg424G
pfg424T
我想使用 file_names.txt
并使用 sed
命令进入 example.conf
:
example.conf
{
"ExomeGermlineSingleSample.sample_and_unmapped_bams": {
"flowcell_unmapped_bams": ["/groups/cgsd/alexandre/gatk-workflows/src/ubam/pfg022G.unmapped.bam"],
"unmapped_bam_suffix": ".unmapped.bam",
"sample_name": "pfg022G",
"base_file_name": "pfg022G.GRCh38DH.target",
"final_gvcf_base_name": "pfg022G.GRCh38DH.target"
},
sed 命令会将 example.conf
上的 pfg022G
替换为 pfg022T
,这是 file_names.txt
(sed s/pfg022G/pfg022T/
) 中的下一项。此时的 example.conf
应该是这样的:
{
"ExomeGermlineSingleSample.sample_and_unmapped_bams": {
"flowcell_unmapped_bams": ["/groups/cgsd/alexandre/gatk-workflows/src/ubam/pfg022T.unmapped.bam"],
"unmapped_bam_suffix": ".unmapped.bam",
"sample_name": "pfg022T",
"base_file_name": "pfg022T.GRCh38DH.target",
"final_gvcf_base_name": "pfg022T.GRCh38DH.target"
},
15 分钟后替换应该是 pfg022T
到 pfg068T
等等,直到 file_names.txt
中的所有项目都用完。
与周期性的 cron 作业相比,创建 daemon/background 进程可能更容易。
while read str;
do
sleep 900;
sed -ri "s@(^\"flowcell_unmapped_bams.*gatk-workflows/src/ubam/)(.*)(\.unmapped\.bam\"\],.*$)@$str@;s/(^\"sample.name.*: \")(.*)(\",.*$)/$str/;s/(^\"base_file_name.*: \")(.*)(\.GRCh38DH.*$)/$str/" example.conf;
done < file_names.txt &
通过while循环逐行读取file_names.txt的内容,将行读取为变量str。休眠 900 秒,然后在三个 sed 命令中使用这个 str 变量。在所有命令中,使用 -r 或 -E 启用正则表达式解释并将行分成三部分。替换第 1 部分的行,然后是变量 str 和第 3 部分。在末尾添加 & 到 运行 进程到后台。
对于我认为这将如何工作的逻辑,
- 创建一个 cronjob,或者如果您的服务器定期关闭,则创建一个 anacron 作业,每 15 分钟 运行 一个 bash 脚本。
- 在 bash 脚本中,您可以使用
if
语句,您可以使用grep
测试filenames.txt
中的每一行,哪一行存在于 example.conf 中, 如果该行存在则转到filenames.txt
中的下一行。如果您在file_names.txt
中的最后一个字符串处,那么 bash 脚本应该停止 运行exit
命令 - 您将 运行 sed 命令替换您的字符串。我确实认为
replace
命令应该能够取代它。 - 如果您必须重新加载服务以加载修改后的配置,然后再添加此配置。
以下 crontab 会 运行 您的脚本每 15 分钟:
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7)
# | | | | |
# * * * * * command to be executed
15 * * * * /path/to/script
有script
阅读
#!/usr/bin/env sh
file1="file_names.txt"
file2="example.conf"
sed -i -e "$(awk '(NR>1){print "s/"p"/""/g"}{p=}' $file1 | tac)" example.conf
我们在这里使用的技巧是进行敬畏替换。文件 example.conf
始终只包含一个也在“file_names.txt”中的字符串。因此,如果您尝试从最后一个替换到前面,您只会进行一次替换。
我们在这里使用 awk
来构建一个 sed
-脚本,并使用 tac
来反转它,这样我们只有一个匹配项:
$ awk '(NR>1){print "s/"p"/""/g"}{p=}' $file_names.txt
s/pfg022G/pfg022T/g
s/pfg022T/pfg068T/g
s/pfg068T/pfg130T/g
s/pfg130T/pfg181G/g
s/pfg181G/pfg181T/g
s/pfg181T/pfg424G/g
s/pfg424G/pfg424T/g
如果我们用上面的脚本做一个sed
,我们总是会以pfg424T
(最后一个条目)结束,因为它会找到一个匹配项(假设我们在第三个条目中pfg068T
),因此 sed 将在此之后执行所有替换。但是,当我们颠倒顺序时(使用 tac
),sed
只会找到一个匹配项。
我可能会提前在队列目录中生成所有文件,并让 cron
作业在每次调用时选择下一个文件。
awk 'NR==FNR { a[++n] = [=10=]; next }
{ file = ".conf"
for(i=1; i<=n; i++) {
l = a[i]; sub("{{name}}", [=10=], l);
print l >file }
close file
}' - file_names.txt <<\____
{
"ExomeGermlineSingleSample.sample_and_unmapped_bams": {
"flowcell_unmapped_bams": ["/groups/cgsd/alexandre/gatk-workflows/src/ubam/{{name}}.unmapped.bam"],
"unmapped_bam_suffix": ".unmapped.bam",
"sample_name": "{{name}}",
"base_file_name": "{{name}}.GRCh38DH.target",
"final_gvcf_base_name": "{{name}}.GRCh38DH.target"
},
____
运行 在您的示例中 file_names.txt
创建以下文件:
pfg022G.conf pfg068T.conf pfg181G.conf pfg424G.conf
pfg022T.conf pfg130T.conf pfg181T.conf pfg424T.conf
内容如您所愿;这是 pfg0222G.conf
:
{
"ExomeGermlineSingleSample.sample_and_unmapped_bams": {
"flowcell_unmapped_bams": ["/groups/cgsd/alexandre/gatk-workflows/src/ubam/pfg022G.unmapped.bam"],
"unmapped_bam_suffix": ".unmapped.bam",
"sample_name": "pfg022G",
"base_file_name": "pfg022G.GRCh38DH.target",
"final_gvcf_base_name": "pfg022G.GRCh38DH.target"
},
现在,您的 cron
作业只需要将其中一个移动到 example.conf
并进行处理。当包含文件的目录为空时,您就完成了。
#!/bin/sh
for f in confdir/*.conf; do
if [ -e "$f" ]; then
# Safeguard against clobbering previous run
if [ -e ./example.conf ]; then
echo "[=13=]: example.conf is still there -- skipping this run" >&2
exit 63
fi
mv "$f" ./example.conf
exec your_main_script_or_whatever
# Should never fall through to here, but whatever
break
else
echo "[=13=]: directory empty -- aborting" >&2
fi
done
为了避免竞争条件——如果之前的 cron
作业仍然是 运行,或者由于某种原因失败了,我们不想破坏它的输入文件。这需要 your_main_script_or_whatever
在完成时删除 example.conf
。如果你不关心这个,也许你可以简单地从上面的脚本中删除保护条件。