在bash脚本中的条件命令

huangapple go评论76阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2023年8月10日 19:57:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76875546.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定