공간이 아직 차지하고있는 ‘덮어 쓰기’파일이 손실됩니까? if [ -d “$file” ];

그래서 바보 인내심은 19.04 서버에서 다음 스크립트를 사용하여 많은 비디오 파일을 접두사가있는 폴더로 옮기려고했습니다.

dirs=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
shopt -s nocasematch

for file in *
do
    for dir in "${dirs[@]}"
    do

     if [ -d "$file" ]; then
      echo 'this is a dir, skipping'
      break
     else
      if [[ $file =~ ^[$dir] ]]; then
       echo "----> $file moves into -> $dir <----"
       mv "$file" "$dir"
       break
      fi
     fi
  done
done

잘못되었다는 단서가 없지만 파일을 폴더로 옮기는 대신 단일 출력으로갔습니다.

----> a1.ts moves into -> A <----
----> a2.ts moves into -> A <----
----> a3.ts moves into -> A <----
----> a4.ts moves into -> A <----
----> a5.ts moves into -> A <----
----> c1.ts moves into -> C <----
----> c2.ts moves into -> C <----
----> c3.ts moves into -> C <----
----> c4.ts moves into -> C <----
----> c5.ts moves into -> C <----

의도 한대로 진행되지 않고 전체 폴더를 거치지 않는 즉시 프로세스 (CTRL + C)를 중지했습니다.

그래서 지금 나는 그 파일을 가지고 AC적은 기가보다, 그것의 모양에 의해 하나의 비디오입니다.

폴더 자체의 총 디스크 사용량에는 50Gb가 고려되지 않았지만 컴퓨터의 전체 디스크 공간은 동일하게 유지되었습니다. 파일이 삭제되지 않았다고 생각합니까?

어떤 도움을 주셔서 감사합니다 🙂

편집 : 파일이 실제로 사라졌고, 마지막으로 쓰여진 파일 만 남았습니다. 디스크 사용 정보를 업데이트하는 데 시간이 걸렸습니다. 이야기의 도덕은 전에 모의 파일에서 스크립트를 실행하십시오!



답변

이것이 문제라고 생각합니다. 디렉토리 A, B, C … Z를 작성해야합니다. 그렇게하면 mv명령이 파일을 해당 디렉토리로 이동해야합니다.

그러나 그렇지 않은 경우 mv명령은 파일을 이름이 A, B, C … 인 파일로 이동하며 이것이 당신이 한 것이라고 생각합니다.

셸 스크립트를보다 안전하게하려면 이동을 시작하기 전에 디렉토리가없는 경우 디렉토리를 작성해야합니다.

dirs=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)

for dir in "${dirs[@]}"
do
 mkdir -p $dir
done

더 안전한 것을 원한다면 옵션 mv과 함께 사용할 수도 있습니다-i

   -i, --interactive
          prompt before overwrite


답변

@Sudodus는 이미 무엇이 잘못되었는지 설명 했지만 다음에 더 간단한 스크립트 버전을 소개합니다.

for letter in {a..z}; do
    dir=${letter^}
    mkdir -p -- "$dir"
    mv -- "$letter"* "${letter^^}"* "$dir"/
done

설명

  • for letter in {a..z}; do: 와 {a..z}사이의 모든 소문자로 확장됩니다 .az

    $ echo {a..z}
    a b c d e f g h i j k l m n o p q r s t u v w x y z

    따라서 모든 소문자를 반복하여 각을로 저장합니다 $letter.

  • dir=${letter^}: 구문 ${var^^}$var대문자로 된 첫 번째 문자 가있는 변수의 내용을 반환합니다 (이 문자 는 하나만 있기 때문에 필요한 전부입니다). 경우에 따라서, $letter이다 a, 그 다음 ${letter^^}이며 A, 따라서 $dir현재의 대문자 버전이 될 것입니다 $letter.

  • mkdir -p -- "$dir": 디렉토리를 만듭니다. 이미 존재하면 아무 것도하지 마십시오 ( -p). 는 -- 옵션의 끝을 의미 하고,로 시작하는 이름을 방지하는 데 유용합니다 -.
  • mv -- "$letter"* "${letter^}"* "$dir" : 모든 파일 (또는 디렉토리)을 관련 대상으로 이동하십시오.

이것의 문제점은 가지고있는 디렉토리를 이동할 것입니다. 아직 존재하지 않거나 대상 디렉토리로 이동하려고 시도하지만 대상 디렉토리가 아닌 기존 디렉토리는 이동하므로 대상 디렉토리는 이동하지 않습니다.

이것이 문제라면, 다음과 같이해야합니다 :

for file in *; do
    if [[ ! -d "$file" ]]; then
        letter="${file:0:1}"
        dir="${letter^}"
        mkdir -p -- "$dir"
        mv -- "$file" "$dir"/
    fi
done


답변

많은 반복을 생성하는 사전 배열에 대해 모든 파일을 검사하는 대신 패턴과 파일을 일치시킬 수 있습니다.

매우 기본적인 정렬 :

#!/bin/bash

videos=./videos
sorted=./sorted

# sort types link,move.
sort_type=link

find "$videos" -maxdepth 1 -type f \
   \( -name '*.avi' -o -name '*.mkv' -o -name '*.mp4' \) -print0 |

while IFS= read -r -d ''; do

    b=$(basename "$REPLY")
    c=${b::1}

    case $c in
        [a-zA-Z]) label=${c^} ;; [0-9]) label="0-9" ;; *) label="_" ;;
    esac

    [[ ! -d "$sorted/$label" ]] && mkdir -p "$sorted/$label"

    if [[ -L $sorted/$label/$b ]] || [[ -e $sorted/$label/$b ]]; then
        echo "File/link: '$b' exists, skipping."
        continue
    fi

    case $sort_type in
        link)
            ln -rfst "$sorted/$label" -- "$REPLY"
            ;;
        move)
               mv -t "$sorted/$label" -- "$REPLY"
            ;;
    esac
done


답변

.bashrc의 보호 :

alias mv="mv -n --backup=numbered"


답변

기록을 위해 mv기존 파일 덮어 쓰기 를 중지 하는 몇 가지 방법 :

  • 디렉토리로 이동하려면 대상에 슬래시를 추가하십시오 (예 : mv "$file" "$dir"/대신 사용) mv "$file" "$dir". 경우 $dir존재하지 않거나 디렉토리지지 않습니다, mv불평 할 것이다 :

    $ touch a
    $ mv a z/
    mv: cannot move 'a' to 'z/': Not a directory
    $ touch z
    $ mv a z/
    mv: failed to access 'z/': Not a directory

    이것은 시스템 호출을하는 것처럼 보이 rename("a", "z/")므로 누군가가 같은 파일 세트를 동시에 처리하는 경우에 대비하여 점검 시점부터 사용 시점까지의 취약점으로부터 안전해야합니다.

  • 또는을 사용하십시오 mv -t "$dir" "$file". 다시 말하지만 $dir디렉토리가 아닌 경우 불평합니다 .

  • -n기존 파일 덮어 쓰기를 방지 하려면이 옵션을 사용하십시오 .

    -n, --no-clobber
        do not overwrite an existing file

    첫 번째 파일의 이름을 바꾸는 것을 막지는 않지만 다른 파일과 함께 휴지통에 버리지 않습니다.

    이것은 평범한 것처럼 보이 rename()므로 동시 처리로 안전하지 않을 수 있습니다. renameat2()덮어 쓰기를 방지하기 위해 플래그를 지원하는 것이 있습니다 .


답변

분명히 당신의 경우는 아니지만, 당신이 할 수 있고 파일을 잃지 않을 수 있습니다. 이를 위해서는 다음 두 가지 중 하나가 필요합니다.

  • 동일한 파일에 대한 하나 이상의 ‘하드 링크’가 파일 시스템의 다른 곳에 존재합니다.
  • 하나 이상의 프로세스에 파일이 열려 있습니다

유닉스 파일 시스템은 하나 이상의 디렉토리 항목 이 정확히 같은 파일 내용 을 참조 할 수있게 합니다 . 이것을 ‘ 하드 링크 ‘ 라고합니다 . 일반 (소프트 / 심볼릭) 옵션 없이ln 명령을 사용하여 하드 링크를 만들 수 있습니다 . 파일 내용에 대한 하나 이상의 하드 링크가 존재하는 한 파일 시스템에서이를 재사용하지 않습니다.-s

참고로, 권한은 일반적으로 디렉토리 항목이 아닌 파일 내용에 적용됩니다. 일반 사용자는 때때로 소유 한 파일을 삭제할 수는 root있지만 쓸 수는 없습니다. 삭제 작업은 파일 자체가 아니라 폴더를 수정합니다. )

파일 시스템은 또한 적어도 하나의 프로세스가 파일을 연 경우에만 파일 내용을 재사용하지 않습니다. 디렉토리 항목이 존재하지 않더라도 파일 시스템은 프로세스가 열릴 때까지 여유 공간을 고려하지 않습니다. 이 파일은 복구 할 수있는 가상 파일 시스템에서 /proc/<pid>/fd에 의해 root한 파일이 열린 상태로 유지한다. (@fluffysheap 감사합니다.)


답변