Bash:在while循环中的大括号内设置数组? (子壳问题)

时间:2011-08-09 16:32:12

标签: arrays bash shell subshell

我在获取变量"${Error[*]}"时遇到问题,变量{ stuff...; }是一个常规的索引数组,从声明它的时间开始保持设置。在我看来,必须启动一个子shell,因此声明不会坚持。在使用大括号Error时,我认为没有打开子shell。我想知道如何让我的变量TestFunction () { unset Error local archive="$1" extlist="$2" && local ext="${archive##*.}" shopt -s nocasematch local -i run=0 while [[ "$run" == 0 || -n "${Error[run]}" ]]; do (( run++ )) local IFS=$'\n\r\t ' if [[ ! "${Error[*]}" =~ 'cpio' && "$ext" =~ ^(pax|cpio|cpgz|igz|ipa|cab)$ && -n "$(which 'cpio')" ]]; then ## Try to cpio the archive. Since cpio cannot handle '.cab' archive, I want to declare an Error ## { cpio -ti --quiet <"$archive" 2>'/dev/null' || local -a Error[run]='cpio'; } | grep -Ei '$extlist' elif [[ ! "${Error[*]}" =~ 'zipinfo' && "$ext" =~ ^(zip|[jw]ar|ipa|cab)$ && -n "$(which 'unzip')" ]]; then ## If cpio fails, then try zipinfo, or unzip on the next run through the loop... ## if which 'zipinfo' &>'/dev/null'; then { zipinfo -1 "$archive" 2>'/dev/null' || local -a Error[run]='zipinfo'; } | grep -Ei "$scanlist" elif which 'unzip' &>'/dev/null'; then { unzip -lqq "$archive" 2>'/dev/null' || local -a Error[run]='unzip'; } | gsed -re '/^ +[0-9]+/!d;s|^ +[0-9]+ +[0-9-]+ [0-9:]+ +||' | grep -Ei "$exlist" fi ## many more elifs... ## fi done shopt -u nocasematch return 0 } Archives='\.(gnutar|7-zip|lharc|toast|7zip|boz|bzi?p2?|cpgz|cpio|gtar|g?z(ip)?|lzma(86)?|t[bg]z2?|ar[cgjk]|bz[2a]?|cb[7rz]|cdr|deb|[dt]lz|dmg|exe|fbz|fgz|gz[aip]|igz|img|iso|lh[az]|lz[hmswx]?|mgz|mpv|mpz|pax|piz|pka|[jrtwx]ar|rpm|s?7-?z|sitx?|m?pkg|sfx|nz|xz)$' IFS=$'\n' declare -a List=($(TestFunction '/Users/aesthir/Programming/│My Projects│/Swipe Master/Test Folder/SDKSetup.cab' "$Archives")) IFS=$' \t\n' 坚持我想写的情况。这是我的脚本示例:

  〔xtrace〕 unset Error
  〔xtrace〕 local 'archive=/Users/aesthir/Programming/│My Projects│/Swipe Master/Test Folder/SDKSetup.cab' 'extlist=\.(gnutar|7-zip|lharc|toast|7zip|boz|bzi?p2?|cpgz|cpio|gtar|g?z(ip)?|lzma(86)?|t[bg]z2?|ar[cgjk]|bz[2a]?|cb[7rz]|cdr|deb|[dt]lz|dmg|exe|fbz|fgz|gz[aip]|igz|img|iso|lh[az]|lz[hmswx]?|mgz|mpv|mpz|pax|piz|pka|[jrtwx]ar|rpm|s?7-?z|sitx?|m?pkg|sfx|nz|xz)$'
  〔xtrace〕 local ext=cab
  〔xtrace〕 shopt -s nocasematch
  〔xtrace〕 local -i run=0
  〔xtrace〕 [[ 0 == 0 ]]
  〔xtrace〕 ((  run++  ))
  〔xtrace〕 local 'IFS=
'
  〔xtrace〕 [[ ! '' =~ cpio ]]
  〔xtrace〕 [[ cab =~ ^(pax|cpio|cpgz|igz|ipa|cab)$ ]]
  〔xtrace〕 which cpio
  〔xtrace〕 [[ -n /usr/bin/cpio ]]
  〔xtrace〕 grep -Ei '$extlist'
  〔xtrace〕 cpio -ti --quiet
  〔xtrace〕 local -a 'Error[run]=cpio'
  〔xtrace〕 [[ 1 == 0 ]]
  〔xtrace〕 [[ -n '' ]]          ## <—— Problem is here... when checking "${Error[run]}", it's unset ##
  〔xtrace〕 shopt -u nocasematch
  〔xtrace〕 return 0


xtrace输出:

cpio

<小时/> 现在显然我知道zipinfounzipTestFunction无法处理cab文件......我故意将'cab'放在扩展名列表中以导致错误。

我希望留在cabextract并继续使用不同的归档程序循环,直到成功(文件列表被转储,TestFunction () { unset Error local archive="$1" extlist="$2" && local ext="${archive##*.}" local -i run=0 while [[ "$run" == 0 || -n "${Error[run]}" ]]; do (( run++ )) local IFS=$'\n\r\t ' if [[ ! "${Error[*]}" =~ 'cpio' && "$ext" =~ ^(pax|cpio|cpgz|igz|ipa|cab)$ && -n "$(which 'cpio')" ]]; then cpio -ti --quiet <"$archive" 2>'/dev/null' || local -a Error[run]='cpio' fi done shopt -u nocasematch return 0 } 在这种情况下很乐意这样做)而不重复已经失败的归档程序。

最后,因为这很好......

grep

...我必须假设问题是大括号,因为我想立即得到结果Error[run]。但是,我需要那些大括号,因为如果grep没有结果,只有当cpio失败时,我才不想设置TestFunction。由于其他原因,我不想在echo 'cpio'之外进行grep(我必须完全重写)。

没有大规模改写的任何快速解决方案?也许read -u6对某些fd和for loop | grep以某种方式?

我更喜欢必须将数组设置到文件列表,然后{{1}}通过每个文件,因为它会减慢速度。

谢谢你们!

- Aesthir

1 个答案:

答案 0 :(得分:3)

问题不是支撑,而是管道。因为您正在使用管道,所以Error [run]的赋值发生在子shell中,因此当子shell退出时,赋值会消失。

变化:

{ cpio -ti --quiet <"$archive" 2>'/dev/null' || local -a Error[run]='cpio'; } | grep -Ei '$extlist'

为:

cpio -ti --quiet <"$archive" 2>'/dev/null' | grep -Ei "$extlist"
[[ ${PIPESTATUS[0]} -ne 0 ]] && Error[run]='cpio'

(顺便说一句,在grep部分需要双引号)