是否可以对目录列表进行“分区” - 例如分成一定数量的块,以对每个“范围”执行不同的操作?
例如,假设我在另一个文件夹中有以下目录:
$ ls test
abc/
def/
hij/
klm/
nop/
qrs/
tuv/
wxy/
zzz/
我想对前 3 个目录执行一些操作,对后 3 个目录执行另一个操作,依此类推。
我的想法是,基于类似的输出,也许跨数字的循环会起作用ls | nl
(但在有人提到它之前,我知道解析ls
是一个禁忌!)
这显然行不通,但我希望说明了我的观点:
for dir in `ls | nl`;
do
do-something-with ${dir{1..3}} # Where $dir has taken on some numerical value linked to the folder)
do-something-with ${dir{4..6}}
# And so on...
do-something-with ${dir{n-3..n}}
done
我打算实际执行此操作的文件夹可以按任何顺序进行处理(即最终的分割可以完全任意),但它们没有逻辑命名一致性 - 我的意思是它们不能按字母或数字顺序合理地组织基于目录名称本身中的任何键。
答案1
没有理由执行以下任一操作错误对于这种情况:
- 使用不可移植的 GNU 扩展(例如
xargs -0
) - 仅将文件名解析为文本流,假装它们不能包含换行符。
您可以毫无困难地轻松处理此问题:
set -- */
while [ "$#" -gt 0 ]; do
case "$#" in
1)
my-command "$1"
shift 1
;;
2)
my-command "$1" "$2"
shift 2
;;
*)
my-command "$1" "$2" "$3"
shift 3
;;
esac
done
实际上,这比必要的更冗长,但这样是可读的。
对于不同类型的分区,您想要将所有目录拆分为三种不同的处理方法(但不需要同时处理它们),您可以这样做:
x=1
for d in *; do
[ ! -d "$d" ] && continue
case "$x" in
1)
# do stuff with "$d"
;;
2)
# do stuff with "$d"
;;
3)
# do stuff with "$d"
;;
esac
x=$(($x+1))
[ "$x" -eq 4 ] && x=1
done
答案2
和printf/xargs
:
printf "%s\0" */ | xargs -0 -n3 echo do-something
printf
打印当前目录内容(以空分隔)。后面的斜杠*
只匹配目录,不匹配文件。xargs
读取以 null 分隔的输入-0
-n3
将输入分为 3 部分。
输出(带有示例目录):
do-something abc/ def/ hij/
do-something klm/ nop/ qrs/
do-something tuv/ wxy/ zzz/
答案3
有时可以为此使用参数-n
to 。xargs
如果您想并行运行作业,-P
也可以使用该选项。
/tmp/t$ ls -1
dir1
dir2
dir3
dir4
/tmp/t$ ls -1 |xargs -n 3 echo runcmd
runcmd dir1 dir2 dir3
runcmd dir4
不要太担心解析 的输出ls|nl
。如果您需要担心此类事情,可以使用xargs 的find .. -print0
参数-0
。 (假设两者都可用)。
答案4
由于通配符的解决方案是我最终使用的解决方案,我已将他的答案标记为已接受,但如果它对将来偶然发现此问题的人有用,下面是我在其他 11 个目录中均匀分配 330 个目录的代码。
也许值得指出的是,它看起来也非常快!
#!/bin/bash
numdirs=11
for ((i=1; i<=$numdirs; i++))
do
mkdir -p ~/simulation_groups/group_${i}
done
x=1
for d in * ; do
[ ! -d "$d" ] && continue
case "$x" in
1)
mv $d ~/simulation_groups/group_${x}
;;
2)
mv $d ~/simulation_groups/group_${x}
;;
3)
mv $d ~/simulation_groups/group_${x}
;;
4)
mv $d ~/simulation_groups/group_${x}
;;
5)
mv $d ~/simulation_groups/group_${x}
;;
6)
mv $d ~/simulation_groups/group_${x}
;;
7)
mv $d ~/simulation_groups/group_${x}
;;
8)
mv $d ~/simulation_groups/group_${x}
;;
9)
mv $d ~/simulation_groups/group_${x}
;;
10)
mv $d ~/simulation_groups/group_${x}
;;
11)
mv $d ~/simulation_groups/group_${x}
;;
esac
x=$(($x+1))
[ "$x" -eq $numdirs+1 ] && x=1
done