동일한 이름을 가진 하위 디렉터리를 디렉터리에서 검색한 다음 하위 디렉터리의 모든 파일을 상위 디렉터리로 이동하는 방법이 필요합니다. 따라서 다음과 같은 방법을 사용하여 빈 디렉터리를 모두 삭제할 /recup-dir1/recup-dir1/files to /recup-dir1/files.
수 있으므로 하위 디렉터리를 비워 둘 수 있습니다.
find . -type -d -empty -delete
그래서 문제는 어떤 디렉토리에 같은 이름의 하위 디렉토리가 있고 어떤 디렉토리에는 없는지 알 수 없다는 것입니다.
의사코드에는 이와 같은 것이 필요합니다.
While more directories are unchecked
get name-x of next dir
enter dir
If name-x/name-x exist
move all files in name-x/name-x to name-x
mark dir as done
next
내 추측으로는 작은 Python 스크립트를 만들어 동일한 이름을 가진 하위 디렉터리가 포함된 모든 디렉터리 목록을 만들고 다음과 같은 명령을 사용하여 이 목록을 반복하는 것입니다.
find something something -exec mv
어쩌면 이는 bash 스크립트를 통해 수행될 수도 있고 다른 솔루션이 존재할 수도 있습니다. 일부 rsync 명령과 비슷하지만 rsync를 사용하여 이 혼란을 만들었을 수 있으므로 이것이 해결책이라고 생각하지 않습니다.
편집: 이것은 트리 출력의 실제 부분입니다. 최상위 디렉터리는 /mnt/external-disk/tst-backup 안에 있으며 하위 수준에는 하위 디렉터리가 없습니다.
│ └── recup_dir.1
├── recup_dir.10
│ └── recup_dir.10
├── recup_dir.100
│ └── recup_dir.100
├── recup_dir.102
│ └── recup_dir.102
└── recup_dir.1020
└── recup_dir.1020
답변1
이를 통해 zsh
다음을 수행할 수 있습니다.
for dir in **/*(NDodoN/e['[[ $REPLY:t = $REPLY:h:t ]]']); do
contents=($dir/*(NDoN))
(( $#contents == 0 )) ||
mv -- $contents $dir:h/ &&
rmdir -- $dir
done
어디:
**/*(qualifiers)
glob 한정자를 사용한 재귀적 globbingN
:nullglob: 일치하는 항목이 없어도 불평하지 마세요.D
: dotglob: 숨겨진 파일을 포함합니다.od
: 순차적 깊이 우선(잎이 자신이 있는 가지보다 먼저 옴)oN
: 그렇지 않으면 파일 목록을 정렬하는 데 신경 쓰지 마세요./
:디렉토리 유형 파일로 제한됩니다.e['expression']
:expression
코드가 true를 반환하는 파일을 제한합니다(현재 파일 경로가 저장되는 위치$REPLY
).$REPLY:t
: 파일의 꼬리(기본 이름)$REPLY:h:t
: 파일 헤더의 끝(디렉토리 이름))
bash
4.4+ 및 GNU find
또는 대부분의 BSD 의 경우 find
다음과 같이 할 수 있습니다.
shopt -s nullglob dotglob
readarray -td '' dirs < <(
LC_ALL=C find . -depth -regex '.*\(/[^/]*\)\1' -type d -print0
)
for d in "${dirs[@]}"; do
contents=("$d"/*)
(( ${#contents[@]} == 0 )) ||
mv -- "${contents[@]}" "${d%/*}/" &&
rmdir -- "$d"
done
./path/to/dir/dir
이번에는 기본 정규식을 사용하여 역참조된 파일을 일치시키는 데 정규식이 사용됩니다 .
답변2
find
GNU v4.8.0 및 Bash v5.1.8을 기반으로 시도해 보세요.
1부: 디렉터리 트리 구문 분석 + 중복된 하위 디렉터리 이름 감지
트리의 디렉터리 구조가 다음과 같다고 가정합니다.
./
|__test1/
|__dirname with space
| |__test2
| |__ test2
|__dirname **
| |__test1
|
|__reboot
| |__test1
|
|__test2/
|__test3/
|__test2/
|__test1/
|__test1/
(이상한 디렉토리 이름은 코드 보안을 위한 것입니다.)
일부 하위 디렉터리(하위 디렉터리)가 다른 방식으로 반복되는 것을 볼 수 있습니다. 일부는 한 번이 아닌 여러 번 반복하고(예: test1
) 반복하지 않으며( test3
) 부모 및 하위 디렉터리로 반복하거나 여러 개의 중간 하위 디렉터리로 분리될 수 있습니다.
아래 코드는 디렉터리 구조의 하위 디렉터리 이름 스푸핑을 자세히 보여줍니다.
- 파일 트리를 구문 분석하여 다음에서 시작하는 하위 디렉터리 구조를 가져옵니다.
$PWD
- 루트 수준( )을 계산하지 않고 2개 이상의 수준에서 하위 디렉터리 경로의 모든 구성 요소에 대한 중복을 찾습니다
$PWD
. 내 실험에서 가장 긴 하위 디렉터리 경로는 다음과 같습니다../test1/test2/test1/test3/test2/test1/test1
- 리프부터 시작하여 각 하위 디렉터리 수준에서 발견된 첫 번째 하위 디렉터리 복사본을 인쇄합니다. 즉, 하위 디렉터리 경로를 오른쪽에서 왼쪽으로 읽습니다.
- 인쇄 시 역순으로 파일이 리디렉션되므로 가장 긴 하위 디렉터리 경로가 먼저 표시됩니다. 두 개의 연속 세미콜론은 경로 구성 요소(";;" 왼쪽)를 이전 글머리 기호(";;" 오른쪽)를 기반으로 찾은 첫 번째 중복 항목과 구분합니다.
[암호]
$ find ./* -type d -exec bash -c 'set -o noglob; IFS="/" subdir=($(printf "%s " "$1")); dirlevels=$((${#subdir[@]}-1)); dupe="$(awk '\''!($1 in sd) {sd[$1];next} {print $1}'\'' < <(printf "%s\n" ${subdir[@]:1}))";[ $dirlevels -ge 2 ] && [ ! -z "$dupe" ] && (printf "%s/" "${subdir[@]:1}";printf " ;; %s\n" "$(tail -n 1 < <(printf "%s\n" "$dupe"))";)' shellexec {} \; | tac >| tmp.data
$ cat -n tmp.data
1 test1/reboot/test1/ ;; test1
2 test1/dirname with space/test2/test2/ ;; test2
3 test1/test2/test1/test3/test2/test1/test1/ ;; test1
4 test1/test2/test1/test3/test2/test1/ ;; test1
5 test1/test2/test1/test3/test2/ ;; test2
6 test1/test2/test1/test3/ ;; test1
7 test1/test2/test1/ ;; test1
8 test1/dirname **/test1/ ;; test1
2부: 중복된 하위 디렉터리 이름 처리, 콘텐츠 이동
처리는 에 표시된 순서대로 발생합니다 tmp.data
.
- 의 첫 번째 줄 에서
tmp.data
경로의 첫 번째 스푸핑된 이름./test1/test2/test1/test3/test2/test1/test1
은 입니다test1
. 해당 내용을 동일한 이름의 가장 왼쪽 하위 디렉터리로 전송할 수 있습니다../test1/
- 대상의 기존 파일을 삭제하지 않고 콘텐츠가 이동되면 가장 오른쪽 하위 디렉터리 수준이
test1
삭제됩니다. - 2번째 줄을 계속 진행
tmp.data
하고 위의 단계를 반복합니다. - 모든 행이
tmp.data
소비될 때까지 기다립니다.
이 단계에서 질문(질문 작성자: @TomDerks)은 test1/*
6행의 가장 오른쪽 콘텐츠로 무엇을 해야 할까요? 입니다. ~해야 한다모두해당 내용이 동일한 이름의 가장 왼쪽 디렉터리(이 경우 경로의 첫 번째 하위 디렉터리 수준)로 이동됩니까? "모두"에는 다음 파일이 포함됩니까?./test1/test2/test1/
또한하위 디렉토리 test3
와 그 내용은 무엇입니까?
완전한 솔루션(2부)은 이에 달려 있습니다.