【问题标题】:BASH not iterating through arrayBASH 没有遍历数组
【发布时间】:2014-09-03 17:21:02
【问题描述】:

我有一个愚蠢的问题。我一直在尝试创建一个 bash 脚本,用于根据自动生成的 .txt 文件中的路径检查 .tif 文件是否存在。然而,问题是我无法让我的代码回显我的 TIF_PATH 数组的所有内容,它只显示找到的第一个条目。

.txt 文件示例:

INPUT_FILE_DOC_TIF=/home/user/documents/tif.tif

知道我做错了什么吗?如你所见,我是个大菜鸟。

提前致谢。

count_recursive () 
{ 
   command find "${1:-.}" -type f -name "${2:-*}" -print0 | 
       command tr -dc '\0' | command wc -c;
return 0
}



#FIND_TXT = Finds .txt files for the array. 
FIND_TXT=$(find . -type f -name "*.txt")

用于创建数组,并查找自动生成的 .txt 文件。

#Save and change Internal Field Seperator (used to remove potential blank spaces, breaks and seperators)
OLDIFS=$IFS

IFS=$'\n'

#Read all file names into an array
declare -a FILE_ARRAY=($FIND_TXT)

#Restore it 
IFS=$OLDIFS

#Get length of array
declare -a tLen=${#FILE_ARRAY[@]}

#Output path to a new variable, TIF_PATH, via egrep. 
declare -a TIF_PATH=$(egrep "INPUT_FILE_DOC_TIF" "${FILE_ARRAY[$@]}" | sed 's#INPUT_FILE_DOC_TIF=##g')
#Output path without file name. 
#declare -a PISS_PATH=$("${TIF_PATH}" | sed 's/..........$//')

#Use for loop to read all filenames
for (( i=0; i<${tLen}; i++ ));

    do
        echo    "$i"
        echo    "${FILE_ARRAY[$i]}"
        #Can be changed to output all, instead of increment. 
        echo    "${TIF_PATH[$i]}"
        #find . -type f -print | xargs grep ""
        #echo   "${PISS_PATH[$@]}"


        #find . -type f -name "$TIF_PATH")


done

结果:

./txt/asd.txt
/home/user/Documents/Scripts/tiffile.tif
1
./txt/1000001.txt

2
./txt/111100001.txt

3
./txt/0047-001124-000000001.txt

4
./test/0047-001124-000000001.txt

5
./0047-001124-000000001.txt

【问题讨论】:

  • 试试tLen=${#FILE_ARRAY[@]}
  • 不相关,但是:尽量避免使用 UPPERCASE_ONLY 变量名。可能与环境变量发生冲突...
  • 好吧,它不再是一个数组了。好的,我不知道大写变量 - 我会记住这一点!

标签: arrays bash


【解决方案1】:

演示您的问题和可能的解决方案

title() { printf "\n%-80.80s\n" "===[$*]$(printf "%80s" | tr ' ' '=')";}

title "demo output: lines what should go into array"
egrep 'root|daemon' /etc/passwd

title "your solution - puts all lines into arr[1] "
declare -a arr1=$(egrep 'root|daemon' /etc/passwd)
echo "array size: ${#arr1[@]}"
for ((i=0; i<${#arr1[@]}; i++))
do
    echo "$i: ${arr1[$i]}"
done

title  "alternative - creates 3 array elements - but keeps '\n'"
readarray arr2 < <(egrep 'root|daemon' /etc/passwd)
echo "array size: ${#arr2[@]}"
for ((i=0; i<${#arr2[@]}; i++))
do
    echo "$i: ${arr2[$i]}"
done

title "as list, breaks on IFS (default on spaces too) - more elements as lines"
arr3=($(egrep 'root|daemon' /etc/passwd))
echo "array size: ${#arr3[@]}"
for ((i=0; i<${#arr3[@]}; i++))
do
    echo "$i: ${arr3[$i]}"
done

title "as previous breaks on IFS, but only on '\n' "
IFS=$'\r\n' arr4=($(egrep 'root|daemon' /etc/passwd))
echo "array size: ${#arr4[@]}"
for ((i=0; i<${#arr4[@]}; i++))
do
    echo "$i: ${arr4[$i]}"
done
unset IFS

生产

===[demo output: lines what should go into array]===============================
root:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false
_cvmsroot:*:212:212:CVMS Root:/var/empty:/usr/bin/false

===[your solution - puts all lines into arr[1] ]================================
array size: 1
0: root:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false
_cvmsroot:*:212:212:CVMS Root:/var/empty:/usr/bin/false

===[alternative - creates 3 array elements - but keeps '\n']====================
array size: 3
0: root:*:0:0:System Administrator:/var/root:/bin/sh

1: daemon:*:1:1:System Services:/var/root:/usr/bin/false

2: _cvmsroot:*:212:212:CVMS Root:/var/empty:/usr/bin/false


===[as list, breaks on IFS (default on spaces too) - more elements as lines]====
array size: 6
0: root:*:0:0:System
1: Administrator:/var/root:/bin/sh
2: daemon:*:1:1:System
3: Services:/var/root:/usr/bin/false
4: _cvmsroot:*:212:212:CVMS
5: Root:/var/empty:/usr/bin/false

===[as previous breaks on IFS, but only on '\n' ]===============================
array size: 3
0: root:*:0:0:System Administrator:/var/root:/bin/sh
1: daemon:*:1:1:System Services:/var/root:/usr/bin/false
2: _cvmsroot:*:212:212:CVMS Root:/var/empty:/usr/bin/false

【讨论】:

  • 感谢您提供详尽的示例。不过我没有把它修好,所以我决定忘记 Bash 来完成这项任务。
  • @Link 好的,这是你的决定,但这有点奇怪,因为对于基于另一个文件中的列表的基于文件的操作(检查某个文件的存在)是 非常 在 bash 中微不足道...也许您从错误的角度解决了问题(数组和“C/Java”之类的想法..)。 更清晰的问题 - 您想要实现的目标 - 会带来更有用的答案。 例如自动生成的文件有更多行?还是你展示的只有 1 个?还有更多这样的文件吗?怎么办,如果 tiff 存在,如果不存在怎么办?等等……等等……
【解决方案2】:

为什么要将 tLen 创建为数组?

declare -a 创建一个数组,但如果您提供单个值,它只会分配给它的第一个元素。要将列表分配给数组,您必须将列表括在括号中:

TIF_PATH=( $(egrep "INPUT_FILE_DOC_TIF" "${FILE_ARRAY[$@]}" | sed 's#INPUT_FILE_DOC_TIF=##g') )

【讨论】:

  • 好问题。我实际上不知道为什么我将 tLen 创建为一个数组。然而,改变它并没有什么不同。我也尝试将我的代码更改为您建议的代码,但仍然没有运气。如果我创建另一个 for 循环,只是为了迭代 TIF_PATH,它可能会起作用吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-24
  • 1970-01-01
  • 2017-02-03
  • 2019-12-01
相关资源
最近更新 更多