Bash

根據名稱的第一個字母對文件和目錄進行分組並將它們移動到該字母的目錄

  • September 5, 2021

我有一個包含以下內容的目錄:

$ 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

引用自:https://unix.stackexchange.com/questions/645407