Bash
根據名稱的第一個字母對文件和目錄進行分組並將它們移動到該字母的目錄
我有一個包含以下內容的目錄:
$ 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
如果目錄已經存在並且是“獲取第一個字元”的 Ksh/Bash/Zsh 語法,則
-p
告訴mkdir
不要抱怨。${f:0:1}
它在行動中:
$ 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