공간이 아직 차지하고있는 '덮어 쓰기'파일이 손실됩니까?


11

그래서 바보 인내심은 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)를 중지했습니다.

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

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

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

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


3
그리고 스크립트 등을 실행하기 전에 A, B등 의 디렉토리 가 존재 했습니까? 그렇지 않은 경우 파일 이름을 바꿨습니다. 이름이로 시작 a하거나 이름 A이 바뀐 모든 파일 A은 마지막으로 이름이 바뀐 파일 만 유지되고 나머지는 덮어 씁니다. 변수를 호출 dir해도 디렉토리가 생성되지 않습니다!
— mook765

2
그것이 그것을 해석하는 방식이기도합니다. "마지막으로 이름이 바뀐 파일이 살아 남았습니다"ha. 디렉토리가 존재하지 않기 때문에 미리 각각 '터치'를 추가해야합니다. 명확히 주셔서 감사합니다
— 나는 TI 계산기 해요

4
".. 이야기의 도덕 +1 + 전에 모의 파일에서 스크립트를 실행!"
— sudodus

4
이와 같은 문제를 피하기위한 팁 : mv "$file" "$dir/"후행과 함께 사용 /; 경우 다음 $dir존재하지 않는, mv대신 이름 변경의 오류가 발생하지 $file에 $dir. 또한 고려 mv -i하고 mv -n. 그리고 mkdir -p좋은 조치를 위해 항상 움직이기 전에 행동하십시오 .
— marcelm

3
@sudodus 더 나은 도덕적, "항상 데이터를 백업하십시오!".
— Jon Bentley

답변:


15

이것이 문제라고 생각합니다. 디렉토리 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

1
스크립트를 여러 번 실행하는 경우 충돌을 피하기 위해 touch대체물을 추가 하는 것이 mkdir좋을까요?
— 나는 TI 계산기 해요

2
touch이름이 없으면 파일을 작성합니다. 따라서이 경우 원하는 것을 수행하지 않습니다. mkdir -p스크립트 사용을 여러 번 처리 할 수 ​​있습니다.
— sudodus

6
당신이 할 수있는 또 다른 간단한 방법 mv대상이 디렉토리 즉, 때 안전 대상 이름에 후행 슬래시를 추가하는 습관을 얻는 것입니다mv "$file" "$dir/"
— steeldriver가

7

@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

의 차이 무엇입니까 ${letter^}그리고 ${letter^^}, 그들은 동일한 있다면, 왜 사용 ${letter^^}대신은 $dir?
— Fund Monica의 소송

1
@NicHartley ${var^}는 첫 글자 만 ${var^^}대문자로 표기하고 모든 글자는 대문자로 표기합니다. $letter한 글자 만 있기 때문에 여기 에는 아무런 차이가 없습니다 .
— terdon

이것은 명령 $dir에 디렉토리 슬래시를 추가하여 추가 계층을 추가하려는 경우를 제외하고는 완벽한 대답 mv입니다. (현재 단일 형식의 대문자로 된 파일이 있으면 현재 형식에서는 실패합니다)
— Stig Hemmer

@StigHemmer 그렇습니다. 아주 좋은 지적입니다. 감사합니다. 답변이 수정되었습니다.
— terdon

4

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

매우 기본적인 정렬 :

#!/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

어쩌면 내가 잘못했지만 분명히 작동하지 않아 10 개의 파일이 손실되었습니다. REPLY 부분을 잘못 이해하는 데 어려움을 겪고 있습니까? 어떤 남은 의도 모든입니다 (폴더 ABCD 내부 것은 ....) 자체가 그쪽으로 별칭 .. 가리키는 별칭 파일입니다
— 나는 TI 계산기 해요

인수가 제공되지 않은 경우 read 내장 명령으로 읽은 입력 행으로 REPLY를 설정하십시오.
— bac0n

그리고 마지막에 ln -rfst "$ sorted / $ label"- "$ REPLY"를 수행합니다. 왜 우리가 mv로 그것들을 옮겼을 때에이 별칭을 사용합니까?
— 저는

기본적으로 "videos"디렉토리에서 정렬 된 디렉토리로의 링크를 만듭니다. mv를 원한다면 "동영상 이동"의 주석 처리를 제거하고 "동영상 링크"를 주석 처리해야합니다 (심볼릭 링크가 덜 무섭다고 생각합니다)
— bac0n

... 동시에 둘다는 아닙니다.
— bac0n

2

.bashrc의 보호 :

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

1
@ 잔나, 고마워요! 따옴표를 추가했습니다.

.zshrc 파일에 추가하는 것도 유효합니다 (ZSH를 사용하는 경우). 에 사람 MV 는 말한다 -n Do not overwrite an existing file. (The -n option overrides any previous -f or -i options.)그래서는 것이 중요 않습니다 -n 태그는 태그를 수행하기 전에 될 것입니다? 번호 --backup = 각 권리의 두 배를 만들 것은 아닌 비트 과잉 (우주 에너지 / 소모) 동네 짱 - 큰 비디오 파일을 처리 (이야기 테라 바이트) 즉. 감사 !
— 저는 TI 계산기입니다.

2

기록을 위해 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()덮어 쓰기를 방지하기 위해 플래그를 지원하는 것이 있습니다 .


1

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

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

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

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

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


1
파일을 연 상태에서 프로세스가 발생하면 / proc / <pid> / fd에서 파일을 찾아 복구 할 수 있습니다. 참조 superuser.com/questions/283102/...
— fluffysheap
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.