英文:
Bash, using 2 arrays in for loop and then 2 arrays inside the for loop
问题
对于第一个目录结构:
DIRS1="foo bar live1 live2"
SRCDIR1="/mnt/nas/stage/live/live/"
对于第二个目录结构:
DIRS2="test1 test2"
SRCDIR2="/mnt/nas/stage/test/test/"
# 遍历第一个目录结构
for dirname in ${DIRS1}; do
# 转到源同步目录
cd "${SRCDIR1}/${dirname}"
# 获取最新的mux文件名
filename=$(ls -t *.mux 2>/dev/null | head -n 1)
echo $filename
### 这里有额外的代码处理文件,使用了 $dirname
done
# 遍历第二个目录结构
for dirname in ${DIRS2}; do
# 转到源同步目录
cd "${SRCDIR2}/${dirname}"
# 获取最新的mux文件名
filename=$(ls -t *.mux 2>/dev/null | head -n 1)
echo $filename
### 这里有额外的代码处理文件,使用了 $dirname
done
英文:
I have a piece of code that will echo the file in a folders that is described in two variables.
This is fine and works.
However, i now want to list the files on another folder structure. However i cannot get it to list.
DIRS="foo bar live1 live2"
SRCDIR="/mnt/nas/stage/live/live/"
# iterate over all directories
for dirname in "${DIRS}"; do
# go to source sync directory
cd "${SRCDIR}/${dirname}"
# get latest mux file name
filename=`ls -t *.mux 2>/dev/null |head -n 1`
echo $filename
###There is additional code to work on the files here that uses $dirname
done
I would then like to add another directory structure;
DIRS1="foo bar live1 live2"
SRCDIR1="/mnt/nas/stage/live/live/"
DIRS2="test1 test2"
SRCDIR2="/mnt/nas/stage/test/test/"
i have got to
for dirname in ${DIRS1} ${DIRS2}
This works as i get a No such file or directory error,
but then I cannot work out to change my CD variable to SRCDIR2, i did think to put another for loop
for dirpath in ${SRCDIR1} ${SRCDIR2}
cd "${dirpath}/${dirname}"
However this gives a cartesian response. How can i sperate out the to only get DIR1 looking in SRCDIR1 and DIR2 looking in SRCDIR2?
Looking at other answer, i may need to use an array but cannot see how to put this into the code.
答案1
得分: 2
如果您确定目录名称不包含空格,您可以使用一对数组,例如:
DIRS[1]="foo bar live1 live2"
SRCDIR[1]="/mnt/nas/stage/live/live/"
DIRS[2]="test1 test2"
SRCDIR[2]="/mnt/nas/stage/test/test/"
for ((id=1; id<=2; id++))
do
for dir in ${DIRS[id]} # 不用双引号以便单独处理每个条目
do
echo "${SRCDIR[id]}${dir}"
done
done
这将生成:
/mnt/nas/stage/live/live/foo
/mnt/nas/stage/live/live/bar
/mnt/nas/stage/live/live/live1
/mnt/nas/stage/live/live/live2
/mnt/nas/stage/test/test/test1
/mnt/nas/stage/test/test/test2
如果目录名称可能包含空格,此解决方案(未加引号的${DIRS[id]}
)不起作用,考虑以下解决方案:
DIRS[1]="foo bar live1 live2 'foo bar live{1,2}'" # 第5个条目包含一对空格
SRCDIR[1]="/mnt/nas/stage/live/live/"
DIRS[2]="test1 test2"
SRCDIR[2]="/mnt/nas/stage/test/test/"
for ((id=1; id<=2; id++))
do
for dir in ${DIRS[id]} # 以空格分隔
do
echo "${SRCDIR[id]}${dir}"
done
done
这将生成:
/mnt/nas/stage/live/live/foo
/mnt/nas/stage/live/live/bar
/mnt/nas/stage/live/live/live1
/mnt/nas/stage/live/live/live2
/mnt/nas/stage/live/live/'foo
/mnt/nas/stage/live/live/bar
/mnt/nas/stage/live/live/live{1,2}'
/mnt/nas/stage/test/test/test1
/mnt/nas/stage/test/test/test2
如果目录名称可能包含空格,另一种方法是使用硬编码的数组名称和名字引用(declare -n
),例如:
DIRS1=("foo bar live1 live2 'foo bar live{1,2}'") # 第5个条目包含一对空格
SRCDIR1="/mnt/nas/stage/live/live/"
DIRS2=("test1 test2")
SRCDIR2="/mnt/nas/stage/test/test/"
for ((id=1; id<=2; id++))
do
declare -n dirs="DIRS${id}" # 名字引用;第一次dirs是指向DIRS1的指针
declare -n srcdir="SRCDIR${id}" # 名字引用;第一次srcdir是指向SRCDIR1的指针
for dir in "${dirs[@]}"
do
echo "${srcdir}${dir}"
done
done
这将生成:
/mnt/nas/stage/live/live/foo
/mnt/nas/stage/live/live/bar
/mnt/nas/stage/live/live/live1
/mnt/nas/stage/live/live/live2
/mnt/nas/stage/live/live/foo bar live{1,2} # 第5个条目保留空格
/mnt/nas/stage/test/test/test1
/mnt/nas/stage/test/test/test2
请注意:名字引用需要bash 4.2+
。最佳解决方案是使用多维数组(例如,DIRS[1,1]="foo"
),但不幸的是,bash
不支持多维数组。可以通过索引串联(例如,DIRS[1-1]="foo"
)来模拟多维数组,但所需的代码会变得有些混乱。如果感兴趣,可以自行研究这个想法。
英文:
If you know for a fact directory names do not contain whitespace you could use a pair of arrays, eg:
DIRS[1]="foo bar live1 live2"
SRCDIR[1]="/mnt/nas/stage/live/live/"
DIRS[2]="test1 test2"
SRCDIR[2]="/mnt/nas/stage/test/test/"
for ((id=1; id<=2; id++))
do
for dir in ${DIRS[id]} # no double quotes so that each entry is processed separately
do
echo "${SRCDIR[id]}${dir}"
done
done
This generates:
/mnt/nas/stage/live/live/foo
/mnt/nas/stage/live/live/bar
/mnt/nas/stage/live/live/live1
/mnt/nas/stage/live/live/live2
/mnt/nas/stage/test/test/test1
/mnt/nas/stage/test/test/test2
If directory names could contain whitespace this solution (unquoted ${DIRS[id]}
) does not work, consider:
DIRS[1]="foo bar live1 live2 'foo bar live{1,2}'" # 5th entry contains a pair of spaces
SRCDIR[1]="/mnt/nas/stage/live/live/"
DIRS[2]="test1 test2"
SRCDIR[2]="/mnt/nas/stage/test/test/"
for ((id=1; id<=2; id++))
do
for dir in ${DIRS[id]} # split on whitespace
do
echo "${SRCDIR[id]}${dir}"
done
done
This generates:
/mnt/nas/stage/live/live/foo
/mnt/nas/stage/live/live/bar
/mnt/nas/stage/live/live/live1
/mnt/nas/stage/live/live/live2
/mnt/nas/stage/live/live/'foo # 5th entry
/mnt/nas/stage/live/live/bar # broken into
/mnt/nas/stage/live/live/live{1,2}' # 3 parts
/mnt/nas/stage/test/test/test1
/mnt/nas/stage/test/test/test2
If directory names can contain white space then another approach would be to use hard-coded array names and namerefs (declare -n
), eg:
DIRS1=(foo bar live1 live2 'foo bar live{1,2}') # 5th entry contains a pair of spaces
SRCDIR1="/mnt/nas/stage/live/live/"
DIRS2=(test1 test2)
SRCDIR2="/mnt/nas/stage/test/test/"
for ((id=1; id<=2; id++))
do
declare -n dirs="DIRS${id}" # nameref; 1st time dirs is a pointer to DIRS1
declare -n srcdir="SRCDIR${id}" # nameref; 1st time srcdir is a pointer to SRCDIR1
for dir in "${dirs[@]}"
do
echo "${srcdir}${dir}"
done
done
NOTE: namerefs require bash 4.2+
This generates:
/mnt/nas/stage/live/live/foo
/mnt/nas/stage/live/live/bar
/mnt/nas/stage/live/live/live1
/mnt/nas/stage/live/live/live2
/mnt/nas/stage/live/live/foo bar live{1,2} # 5th entry maintains whitespace
/mnt/nas/stage/test/test/test1
/mnt/nas/stage/test/test/test2
As mentioned in comments, the ideal solution would be a pair of multi-dimensional arrays (eg, DIRS[1,1]="foo"
); unfortunately bash
does not support multi-dimensional arrays.
Yes, it is possible to simulate a multi-dimensional array via concatenation of indices (eg, DIRS[1-1]="foo"
) but the necessary code gets a bit messy. I'll leave it to OP to research this idea if it's of interest ...
答案2
得分: 0
给定Bash数组和关联数组的限制,以及使用变量间接方式可能出现的许多陷阱,我会考虑使用类似这样的Shellcheck-干净的代码:
#! /bin/bash -p
# SRCDIR DIRS
# -------------------------- -----------------------
srcdir_dirs=( /mnt/nas/stage/live/live foo bar live1 live2 ''
/mnt/nas/stage/test/test 'test 1' 'test 2' '' )
srcdir='' dirname=''
for d in "${srcdir_dirs[@]}"; do
if [[ -z $d ]]; then
srcdir=''
elif [[ -z $srcdir ]]; then
srcdir=$d
else
dirname=$d
printf '%s/%s\n' "$srcdir" "$dirname"
# ...
fi
done
- 这适用于除古老版本的Bash以外的所有版本(已测试Bash 3和Bash 5)。
- 我已将
test1
和test2
替换为test 1
和test 2
,以演示包含空格的名称不会引起问题。即使名称中包含换行符也是可以的。 srcdir_dirs
中的空字符串(''
)条目用于界定定义源目录和多个子目录的条目组。这是安全的,因为空字符串不是有效的文件或目录名称或路径。srcdir_dirs
数组可以轻松扩展以处理三个或更多源目录。- 有关为什么使用
printf
而不是echo
的解释,请参见接受的并且很好的答案为什么printf比echo好?。
英文:
Given the limitations of Bash arrays and associative arrays, and the many pitfalls associated with using variables indirectly, I'd consider using something like this Shellcheck-clean code:
#! /bin/bash -p
# SRCDIR DIRS
# -------------------------- -----------------------
srcdir_dirs=( /mnt/nas/stage/live/live foo bar live1 live2 ''
/mnt/nas/stage/test/test 'test 1' 'test 2' '' )
srcdir='' dirname=''
for d in "${srcdir_dirs[@]}"; do
if [[ -z $d ]]; then
srcdir=''
elif [[ -z $srcdir ]]; then
srcdir=$d
else
dirname=$d
printf '%s/%s\n' "$srcdir" "$dirname"
# ...
fi
done
- This works with all but ancient versions of Bash (tested with Bash 3 and Bash 5).
- I've replaced
test1
andtest2
withtest 1
andtest 2
to demonstrate that names containing whitespace do not cause problems. Even newlines in names would be OK. - The empty string (
''
) entries insrcdir_dirs
delimit groups of entries that define a source directory and multiple subdirectories. This is safe because the empty string is not a valid file or directory name or path. - The
srcdir_dirs
array can easily be extended to handle three or more source directories. - See the accepted, and excellent, answer to Why is printf better than echo? for an explanation of why I used
printf
instead ofecho
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论