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


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)를 중지했습니다.

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

폴더 자체의 총 디스크 사용량에는 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.