我有一个包含以下内容的目录:
$ mkdir dir && cd "$_"
~/dir $ mkdir a1 a2 a3 a4 b1 c1 c2 1a 2a 2b 2c 2d 3a _1 _2
~/dir $ touch a_1 a_2 a_3 a_4 b_1 c_1 c_2 1_a 2_a 2_b 2_c 2_d 3_a __1 __2
~/dir $ ls
__1 1_a __2 2_a 2_b 2_c 2_d 3_a a_1 a_2 a_3 a_4 b_1 c_1 c_2
_1 1a _2 2a 2b 2c 2d 3a a1 a2 a3 a4 b1 c1 c2
现在我想根据它们的第一个字母对所有这些文件和目录进行分组,并将它们移动到相同字母的目录中。所以输出将是:
~/dir $ ls
_ 1 2 3 a b c
使用exa,树看起来像这样:
~/dir $ exa --tree
.
├── 1
│ ├── 1_a
│ └── 1a
├── 2
│ ├── 2_a
│ ├── 2_b
│ ├── 2_c
│ ├── 2_d
│ ├── 2a
│ ├── 2b
│ ├── 2c
│ └── 2d
├── 3
│ ├── 3_a
│ └── 3a
├── _
│ ├── _1
│ ├── _2
│ ├── __1
│ └── __2
├── a
│ ├── a1
│ ├── a2
│ ├── a3
│ ├── a4
│ ├── a_1
│ ├── a_2
│ ├── a_3
│ └── a_4
├── b
│ ├── b1
│ └── b_1
└── c
├── c1
├── c2
├── c_1
└── c_2
我知道我可以使用通配符移动:
~/dir $ mkdir a && mv a* a
这会引发错误:
mkdir: cannot create directory ‘a’: File exists
但它完成了工作。我可以做这样的事情来避免错误:
~/dir $ mkdir temp && mv a* temp && mv temp a
然后我可以在 for 循环中为我知道的每个字母使用它。但问题是我不知道那些第一个字母可能是什么,我们有很多字母。有没有一种方法可以在不需要知道这些字母的情况下实现这一目标?
只需迭代所有内容:
#!/bin/bash
for f in *; do
firstChar="${f:0:1}";
mkdir -p -- "$firstChar";
mv -- "$f" "$firstChar";
done
该-p
通知mkdir
不抱怨,如果该目录已经存在,并且${f:0:1}
是KSH /猛砸/岩组语法“得到第一个字符”。
这是在行动:
$ mkdir a1 a2 a3 a4 b1 c1 c2 1a 2a 2b 2c 2d 3a _1 _2
$ touch a_1 a_2 a_3 a_4 b_1 c_1 c_2 1_a 2_a 2_b 2_c 2_d 3_a __1 __2
$ ls -F
__1 _1/ 1_a 1a/ __2 _2/ 2_a 2a/ 2_b 2b/ 2_c 2c/ 2_d 2d/ 3_a 3a/ a_1 a1/ a_2 a2/ a_3 a3/ a_4 a4/ b_1 b1/ c_1 c1/ c_2 c2/
$ for f in *; do
firstChar="${f:0:1}";
mkdir -p "$firstChar";
mv -- "$f" "$firstChar";
done
$ tree
.
├── _
│ ├── __1
│ ├── _1
│ ├── __2
│ └── _2
├── 1
│ ├── 1_a
│ └── 1a
├── 2
│ ├── 2_a
│ ├── 2a
│ ├── 2_b
│ ├── 2b
│ ├── 2_c
│ ├── 2c
│ ├── 2_d
│ └── 2d
├── 3
│ ├── 3_a
│ └── 3a
├── a
│ ├── a_1
│ ├── a1
│ ├── a_2
│ ├── a2
│ ├── a_3
│ ├── a3
│ ├── a_4
│ └── a4
├── b
│ ├── b_1
│ └── b1
└── c
├── c_1
├── c1
├── c_2
└── c2
22 directories, 15 files
请注意,如果您可以拥有只有一个字符的现有文件或目录名称,则会导致错误。例如,如果您创建一个名为的文件a
并尝试上述方法,您将获得:
mkdir: cannot create directory ‘a’: File exists
mv: 'a' and 'a' are the same file
如果这是一个问题,您可以执行一些复杂的操作,例如重命名为临时文件、创建目录并将文件移动到其中:
for f in *; do
firstChar="${f:0:1}";
## if the first character exists as a dir, move the file there
if [[ -d "$firstChar" ]]; then
mv -- "$f" "$firstChar";
## if it exists but is not a dir, move to a temp location,
## re-create it as a dir, and move back from temp
elif [[ -e "$firstChar" ]]; then
tmp=$(mktemp ./tmp.XXXXX)
mv -- "$firstChar" "$tmp"
mkdir -p "$firstChar"
mv -- "$tmp" "$firstChar"/"$f"
else
mkdir -p "$firstChar";
mv -- "$f" "$firstChar";
fi
done
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句