英文:
Conditional command in bash scipt
问题
以下是您要翻译的内容:
我现在有一个bash脚本(merge.sh),并且我创建了另一个脚本(merge-all.sh),在新脚本(merge-all.sh)中有一个循环,它调用了merge.sh。我想知道是否有可能条件化merge.sh内的某个命令,以便仅在第一次迭代中运行,因为每次调用它都是一种浪费。
我可以将它移到merge-all.sh上,但我希望merge.sh能够在有或没有其他脚本的情况下都能正常工作。
merge.sh文件如下,问题中的命令是"source init":
#!/bin/sh
#
source /path/init
cd /path_2
INPUT_LIST=/path_3/$1
echo "-----------------------------"
echo "Starting script:" $(basename $BASH_SOURCE)
echo "----------------------------- 0"
echo ${INPUT_LIST}
#hadd -f ${INPUT_LIST%.txt}.root @${INPUT_LIST}
英文:
I have at the moment a bash script (merge.sh) and I made another one that inside the new one (merge-all.sh) there is a loop that calls the merge.sh. I want to see if it is possible to condition one of the commands inside merge.sh to run only in the first iteration, since it is a waste to call it every time.
I could move it on the merge-all.sh, but I want merge.sh to be functional with/out the other script.
The merge.sh file is the following and the command in question is the source init:
#!/bin/sh
#
source /path/init
cd /path_2
INPUT_LIST=/path_3/$1
echo "-----------------------------"
echo "Starting script:" $(basename $BASH_SOURCE)
echo "----------------------------- 0"
echo ${INPUT_LIST}
#hadd -f ${INPUT_LIST%.txt}.root @${INPUT_LIST}
答案1
得分: 1
检查是否存在行为标志,比如一个变量。
$: cat outer
#! bash
for o in {1..3}
do . inner
done
$: cat inner
#! bash
((first++)) || echo on record $o
date -d "+$o days"
$: ./outer
on record 1
Fri Aug 11 08:08:12 CDT 2023
Sat Aug 12 08:08:12 CDT 2023
Sun Aug 13 08:08:12 CDT 2023
相反的逻辑也不难。
$: cat inner
#! bash
if ((skip))
then skip=0
else echo $o
fi
$: ./outer
1
2
3
$: skip=1 ./outer
2
3
更复杂的实现可能会使用命令行选项,但只要这两个脚本都设计用于它,就足够容易集成行为,仍然可以将 "inner" 脚本保留为一个独立可用的脚本。
英文:
Check for a behavior flag such as a variable.
$: cat outer
#! bash
for o in {1..3}
do . inner
done
$: cat inner
#! bash
((first++)) || echo on record $o
date -d "+$o days"
$: ./outer
on record 1
Fri Aug 11 08:08:12 CDT 2023
Sat Aug 12 08:08:12 CDT 2023
Sun Aug 13 08:08:12 CDT 2023
The reverse logic isn't hard either.
$: cat inner
#! bash
if ((skip))
then skip=0
else echo $o
fi
$: ./outer
1
2
3
$: skip=1 ./outer
2
3
A more complicated implementation might use command-line options, but it's easy enough to integrate behavior if both scripts are designed for it, and still leave the "inner" script useful as a standalone.
答案2
得分: 0
以下是翻译好的部分:
"I THINK what you may really want is to have a script merge.sh
that can be called any time to do X (where X is anything that should be done once, e.g. maybe start a daemon) but that script should not do X again if it's already done X. Given that, the fact it's being called in a loop sometimes is irrelevant but framing the question as 'I have a command called from a loop' makes us think that the obvious solution is to just not call it in a loop. The only clue that that might not be the best solution is your statement that 'I want merge.sh to be functional with/out the other script'.
If I'm right then the solution would be to check if X has already been done rather than checking if this is the first time merge.sh
has been called, e.g. by testing for some process running or some environment variable having some value or some value set in some file (and, if the latter, then manage that somehow to ensure the value is cleared when necessary).
For example, I could imagine you having something like this:
$ cat start_foo
foo &;
$ cat start_bar
bar &;
$ cat start_all
while :; do
start_foo
start_bar
sleep 60
done
$ tail -1 .profile:
start_all &;
so you have a script start_all
that runs continuously in the background making sure some set of other background processes are running and so it calls a script per process (e.g. start_foo
) to ensure that process (foo
) is running.
You don't want to start a new foo
process every minute but you also don't want to clutter start_all
with the details of what needs to happen to ensure foo
is running. Given that, you could write start_foo
as (pseudo-code):
$ cat start_foo:
if ! pgrep foo; then
foo &;
fi
That will effective give you what you want, i.e. a script that only does something, foo &;
, the first time it's called (in normal operation where foo
doesn't die) and will work whether called from a loop or not.
Whether the check in start_foo
is for a process running or a file existing or anything else is up to whatever start_foo
or foo
actually does.
In your case you MAY want something like:
#!/bin/sh
INPUT_LIST=/path_3/$1
outfile=${INPUT_LIST%.txt}.root
if [ ! -s "$outfile" ]; then
source /path/init
cd /path_2
echo "-----------------------------"
echo "Starting script:" $(basename $BASH_SOURCE)
echo "----------------------------- 0"
echo ${INPUT_LIST}
hadd -f "$outfile" @${INPUT_LIST}
fi
Check your quotes and capitalization btw - run your script through http://shellcheck.net and read https://stackoverflow.com/questions/673055/correct-bash-and-shell-script-variable-capitalization.
You may also want something like:
$ cat merge.sh
#!/bin/sh
ucl=$2
INPUT_LIST=/path_3/$1
outfile=${INPUT_LIST%.txt}.root
if [ "$ucl" = 1 -o ! -s "$outfile" ]; then
source /path/init
cd /path_2
echo "-----------------------------"
echo "Starting script:" $(basename $BASH_SOURCE)
echo "----------------------------- 0"
echo ${INPUT_LIST}
hadd -f "$outfile" @${INPUT_LIST}
fi
and call it as:
ucl=1
while :; do
merge.sh whatever "$ucl"
ucl=""
done
or some other variation."
英文:
I THINK what you may really want is to have a script merge.sh
that can be called any time to do X (where X is anything that should be done once, e.g. maybe start a daemon) but that script should not do X again if it's already done X. Given that, the fact it's being called in a loop sometimes is irrelevant but framing the question as "I have a command called from a loop" makes us think that the obvious solution is to just not call it in a loop. The only clue that that might not be the best solution is your statement that I want merge.sh to be functional with/out the other script
.
If I'm right then the solution would be to check if X has already been done rather than checking if this is the first time merge.sh
has been called, e.g. by testing for some process running or some environment variable having some value or some value set in some file (and, if the latter, then manage that somehow to ensure the value is cleared when necessary).
For example, I could imagine you having something like this:
$ cat start_foo
foo &
$ cat start_bar
bar &
$ cat start_all
while :; do
start_foo
start_bar
sleep 60
done
$ tail -1 .profile:
start_all &
so you have a script start_all
that runs continuously in the background making sure some set of other background processes are running and so it calls a script per process (e.g. start_foo
) to ensure that process (foo
) is running.
You don't want to start a new foo
process every minute but you also don't want to clutter start_all
with the details of what needs to happen to ensure foo
is running. Given that, you could write start_foo
as (pseudo-code):
$ cat start_foo:
if ! pgrep foo; then
foo &
fi
That will effective give you what you want, i.e. a script that only does something, foo &
, the first time it's called (in normal operation where foo
doesn't die) and will work whether called from a loop or not.
Whether the check in start_foo
is for a process running or a file existing or anything else is up to whatever start_foo
or foo
actually does.
In your case you MAY want something like:
#!/bin/sh
INPUT_LIST=/path_3/$1
outfile=${INPUT_LIST%.txt}.root
if [ ! -s "$outfile" ]; then
source /path/init
cd /path_2
echo "-----------------------------"
echo "Starting script:" $(basename $BASH_SOURCE)
echo "----------------------------- 0"
echo ${INPUT_LIST}
hadd -f "$outfile" @${INPUT_LIST}
fi
Check your quotes and capitalization btw - run your script through http://shellcheck.net and read https://stackoverflow.com/questions/673055/correct-bash-and-shell-script-variable-capitalization.
You may also want something like:
$ cat merge.sh
#!/bin/sh
ucl=$2
INPUT_LIST=/path_3/$1
outfile=${INPUT_LIST%.txt}.root
if [ "$ucl" = 1 -o ! -s "$outfile" ]; then
source /path/init
cd /path_2
echo "-----------------------------"
echo "Starting script:" $(basename $BASH_SOURCE)
echo "----------------------------- 0"
echo ${INPUT_LIST}
hadd -f "$outfile" @${INPUT_LIST}
fi
and call it as:
ucl=1
while :; do
merge.sh whatever "$ucl"
ucl=""
done
or some other variation.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论