我試圖修改陣列來管理一些功能。我想從子外殼訪問陣列 lst 或使用不是命令替換的東西來捕獲函式輸出。
我已經更改了代碼以便更好地理解。
#!/bin/bash
lst=()
function fun(){
match=0
string="$1"
for x in "${lst[@]}"; do
if [[ "$x" = "$string" ]]; then
match=1
break
fi
done
if [[ $match -eq 0 ]]; then
lst =("$string $2")
echo "$1"
else
echo "$string already called"
fi
}
echo ================================= TEST 2.1 =================================
echo "${lst[@]}"
res="$( fun "test" "1")" # first call
echo "$res" - wannted output: test
echo "${lst[@]}"
echo "${lst[@]}"
res="$( fun "test" "**2**")" # secound call
echo "$res" - wannted output: test
echo "${lst[@]}"
echo "${lst[@]}"
res="$( fun "test" "**2**")" # third call
echo "$res" - wannted output: test already called
echo "${lst[@]}"
但是命令 subtition 會打開新的子 shell,所以我無法訪問陣列。
有任何想法嗎?
這是一個更清晰的示例,并修復了明顯的語法問題:
$ cat tst.sh
#!/usr/bin/env bash
fun() {
local -n arr=$1
local str=$2
echo 'done'
arr[0]="$str"
}
printf -- '-------\nNo subshell:\n'
lst=( 'something' )
declare -p lst
fun lst 'foo'
declare -p lst
printf -- '-------\nWith subshell:\n'
lst=( 'something' )
declare -p lst
rec=$( fun lst 'foo' )
echo "$rec"
declare -p lst
$ ./tst.sh
-------
No subshell:
declare -a lst=([0]="something")
done
declare -a lst=([0]="foo")
-------
With subshell:
declare -a lst=([0]="something")
done
declare -a lst=([0]="something")
uj5u.com熱心網友回復:
考慮不使用子shell,而是傳遞rec要通過參考填充的變數:
$ cat tst.sh
#!/usr/bin/env bash
fun() {
local -n arr=$1
local str=$2
local -n rslt=$3
rslt='done'
arr[0]="$str"
}
lst=( 'something' )
declare -p lst
fun lst 'foo' rec
echo "$rec"
declare -p lst
$ ./tst.sh
declare -a lst=([0]="something")
done
declare -a lst=([0]="foo")
或者,請參閱https://unix.stackexchange.com/q/334543/133219或只是谷歌“bash 將變數分配給沒有子外殼的函式的輸出”
uj5u.com熱心網友回復:
第一個問題:
在函式中,您a)進行測驗"$string",然后b)分配"$string $2"給陣列,因此在嘗試"$string"與"$string $2".
假設分配是正確的,那么測驗也應該更改"$string $2"為。當然,如果在子 shell 中呼叫函式,這將無濟于事......
第二期:
在子 shell 中呼叫函式。
雖然這種方法允許您捕獲函式的輸出,但這意味著函式在子 shell 中所做的任何分配都將在子 shell 退出時消失。
a)維護函式分配和b)捕獲函式呼叫的輸出的一種方法是將函式輸出放入變數中(例如,res)。
修改 OP 的當前代碼以解決這兩個問題:
function fun(){
match=0
string="$1"
for x in "${lst[@]}"; do
if [[ "$x" = "$string $2" ]]; then # test the same thing that's assigned to array
match=1
break
fi
done
if [[ $match -eq 0 ]]; then
lst =("$string $2") # assign the same thing that we're testing
res="$1" # place function output in variable
else
res="$string already called" # place function output in variable
fi
}
echo ================================= TEST 2.1 =================================
lst=()
echo "######"
declare -p lst
fun "test" "1" # call function within scope of current shell (ie, no sub-shell required)
echo "$res" - wannted output: test
declare -p lst
echo "######"
declare -p lst
fun "test" "**2**"
echo "$res" - wannted output: test
declare -p lst
echo "######"
declare -p lst
fun "test" "**2**"
echo "$res" - wannted output: test already called
declare -p lst
這會產生:
================================= TEST 2.1 =================================
######
declare -a lst=()
test - wannted output: test
declare -a lst=([0]="test 1")
######
declare -a lst=([0]="test 1")
test - wannted output: test
declare -a lst=([0]="test 1" [1]="test **2**")
######
declare -a lst=([0]="test 1" [1]="test **2**")
test already called - wannted output: test already called
declare -a lst=([0]="test 1" [1]="test **2**")
上述解決方案的一個缺點是函式中的lst陣列和res變數的硬編碼。
使用namerefs(ie, declare -nand local -n) 您可以讓父級將陣列和變數名傳遞給函式。
有關使用 a通過動態命名的變數將輸出從函式傳遞到父級的示例,請參見此答案的第二半。nameref
uj5u.com熱心網友回復:
我不得不使用括號來模仿功能。
解決方案是將輸出寫入一個唯一的檔案并從中讀取
謝謝你的幫助!
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/496507.html
