Function

continue:僅在“for”、“while”或“until”循環中有意義

  • April 8, 2021

我有一個循環來檢查是否跳到下一次迭代(A)的某些標準。我意識到,如果我呼叫一個呼叫 的函式 ( skip) continue,就好像它在子程序中被呼叫,因為它看不到循環 (B)。此外,依賴於 -uating 字元串的建議解決方法也eval不起作用(C)。

# /usr/bin/bash env

skip()
{
   echo "skipping : $1"
   continue   
}

skip_str="echo \"skipping : $var\"; continue"

while read -r var;
do
   if [[ $var =~  ^bar$  ]];
   then
       # A
       #        echo "skipping : $var"
       #        continue
       # B
       #        skip "$var" #  continue: only meaningful in a `for', `while', or `until' loop
       # C
       eval "$skip_str"
   fi
   echo "processed: $var"
done < <(cat << EOF 
foo
bar
qux
EOF
       )

方法C:

$ source ./job-10.sh
processed: foo
skipping : 
processed: qux

另見:

函式在 Bash 中作為子程序執行嗎?

PS1:有人可以提醒我為什麼< <而不是<之後需要done嗎?

PS2:while因此沒有找到標籤for

問題是當你的函式被執行時,它不再在循環中。它不在子外殼中,不,但它也不在任何循環內。就函式而言,它是一段獨立的程式碼,不知道從哪裡呼叫它。

然後,當您執行時eval "$skip_str",沒有任何值,$var因為您設置skip_string$var未定義的時間。這實際上應該像您期望的那樣工作,它只是非常複雜且有風險(如果您不控制輸入 100%),無緣無故:

#! /usr/bin/env bash

while read -r var;
do
 skip_str="echo \"skipping : $var\"; continue"
 if [[ $var =~  ^bar$  ]];
 then
   eval "$skip_str"
 fi
 echo "processed: $var"

done < <(cat << EOF 
foo
bar
qux
EOF
       )

那……真的不是很漂亮。就個人而言,我只會使用一個函式來進行測試,然後對測試的結果進行操作。像這樣:

#! /usr/bin/env bash

doTest(){
 if [[ $1 =~  ^bar$  ]];
 then
   return 1
 else
   return 0
 fi
 
}

while read -r var;
do
 if doTest "$var"; then
   echo "processed: $var"
 else
   echo "skipped: $var"
   continue
 fi

## Rest of your code here

done < <(cat << EOF 
foo
bar
qux
EOF
       )

如果你解釋你的目標是什麼,我可能會給你更好的東西。

最後,你不需要< <after done,你需要< <(). 這<是正常的輸入重定向,<()稱為程序替換,是一種技巧,可讓您將命令的輸出視為文件名。

如果您使用該函式只是為了避免重複諸如 之類的額外內容echo "skipping $1",則可以簡單地將更多邏輯移動到該函式中,以便在那裡有一個循環。像這樣的東西:連結

該函式可以在同一個程序中執行,它只是在語法上與循環不同。在幾乎任何其他程式語言中,您也不能在函式內部使用breakcontinue在函式內部影響其外部的循環。

但實際上,在 shell 中,它是未指定的

continue [n]

如果指定了n,則 continue 實用程序將返回到第n個封閉 for、while 或 until 循環的頂部。如果未指定n,則 continue 的行為就像將n指定為 1 一樣。

$$ … $$ $$ … $$ 如果沒有封閉循環,則行為未指定。

你得到什麼取決於外殼:

Bash 給你錯誤並忽略continue

$ bash -c 'f() { continue; }; for x in a b c; do f; echo $x; done; echo done'
environment: line 0: continue: only meaningful in a ‘for’, ‘while’, or ‘until’ loop
a
environment: line 0: continue: only meaningful in a ‘for’, ‘while’, or ‘until’ loop
b
environment: line 0: continue: only meaningful in a ‘for’, ‘while’, or ‘until’ loop
c
done

Ksh 默默地忽略它:

$ ksh -c 'f() { continue; }; for x in a b c; do f; echo $x; done; echo done'
a
b
c
done

雖然 Dash、Yash 和 Zsh 實際上確實應用了它:

$ dash -c 'f() { continue; }; for x in a b c; do f; echo $x; done; echo done'
done

我確實希望類似的考慮也適用於 using eval,但似乎情況並非如此。至少我看不出貝殼之間有任何區別。

總而言之,不要那樣做。把它寫出來:

while read -r var;
do
   if [[ $var =~  ^bar$  ]];
   then
       echo "skipping '$var'"
       continue
   fi
   echo "processed: $var"
done

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