Bash

bash:使用子shell分配給變數,但如果分配失敗則退出主腳本

  • October 30, 2021

我想要一個 bash 腳本,它允許我呼叫一個函式來查看文件中是否包含某些數據,如果它沒有使主腳本失敗,類似於以下內容,簡化為保留這一點。

這不起作用(當子 shell 失敗時不退出主腳本)。

我該如何編寫require_line函式,這樣我就可以像這樣在一個文件中說出其中的 20 多個

VALUE1=$(require_line "myKey1")
VALUE2=$(require_line "myKey2")
...

並且不需要一個 if 圍繞每個?

#!/bin/bash
set -eo pipefail

VALUE=$(require_line "myKey")

require_line(){
 local KEY=$1
 local DATA=$(cat /tmp/myfile)
 local INFO=$(echo "$DATA" | grep "$KEY")

 if [ ! -z "$INFO" ]
 then
   echo "Key not found in $DATA, key: $KEY"
   exit 1;
 fi
 echo "$INFO"
}

退出 subshel​​l 不會像您經歷的那樣退出主腳本。

我想到了 3 個(半個)解決方案:

  1. 使用set -e這樣任何(“未經測試”)失敗的命令(或子shell)將立即退出主腳本(這可能是矯枉過正或導致其他麻煩),
  2. 從函式發送信號並用trap
  3. || exit $?每次VALUEn=$(...)像這樣使用VALUE=$(require_line "myKey") || exit $?
  4. 使用 .將 (3.) 與(不那麼優雅的)循環結合起來eval

第三個並不完全“需要一個 if 圍繞每個”,並且仍然是一個相當緊湊的語法恕我直言。


順便說一句,這條線

echo "Key not found in $DATA, key: $KEY"

…如果您在此之後立即退出整個腳本,實際上是無用的,因為該句子將儲存在$VALUEn不會顯示的變數中。

我建議列印成stderr這樣:

echo "my error" 1>&2

例子

解決方案 1 的範例

#!/bin/sh
set -e

myfunc(){
       echo $1
       if [ "$1" != "OK" ] ; then exit 1 ; fi
}

VALUE1=$(myfunc "OK") 
echo $VALUE1
VALUE2=$(myfunc "NO WAY") 
echo $VALUE2

echo "main script did not exit"
$ ./test.sh
OK
zsh: exit 1     ./test.sh

但是,如果我set -e從一開始就刪除,我會得到:

$ ./test.sh
OK
NO WAY
main script did not exit

解決方案 2 的範例

#!/bin/sh

trap "exit $?" USR1

myfunc(){
       echo $1
       if [ "$1" != "OK" ] ; then kill -USR1 $$ ; fi 
}

VALUE1=$(myfunc "OK") 
echo $VALUE1
VALUE2=$(myfunc "NO WAY")
echo $VALUE2

echo "main script did not exit"
$ ./test.sh
OK

解決方案 3 的範例

#!/bin/sh

myfunc(){
       echo $1
       if [ "$1" != "OK" ] ; then exit 1 ; fi
}

VALUE1=$(myfunc "OK") || exit $?
echo $VALUE1
VALUE2=$(myfunc "NO WAY") || exit $?
echo $VALUE2

echo "main script did not exit"
$ ./test.sh
OK
zsh: exit 1     ./test.sh

解決方案 4 的範例

#!/bin/sh

myfunc(){
       echo $1
       if [ "$1" != "OK" ] ; then exit 1 ; fi
}

I=1
for key in "OK" "OK" "NO WAY": ; do
       eval "VALUE$I=\$(myfunc \"$key\")" || exit $?
       eval "echo \$VALUE$I"
       I=$(($I+1))
done
echo "main script did not exit"
$ ./test.sh
OK
OK
zsh: exit 1     ./test.sh

引用自:https://unix.stackexchange.com/questions/675346