awk 스크립트에서 ls의 공백 및 아포스트로피 문제 방지

awk 스크립트에서 ls의 공백 및 아포스트로피 문제 방지

두 개의(로컬) 장치에 동일한 파일이 많이 있는데 한 장치(A)의 일부 파일 이름만 바꿨습니다. 장치 A의 새 이름을 기반으로 다른 장치(B)에서 동일한 파일의 이름을 바꾸어 결국 동일한 파일과 이름 파일을 갖게 되는 다음 방법을 찾았습니다.어떠한 내용도 삭제하거나 복사하지 마세요, 그러나 단지이름 바꾸기.

사실 나는 흥미로운 대답을 찾았습니다.여기Hai Vu에서(두 번째 답변)

스크립트일하다, 하지만 두 가지가 있습니다질문:

  1. 그리고공간파일 이름: 공백으로 잘린 이름입니다. 그리고
  2. 그리고페르시아(') 파일 이름에

스크립트(rename-identical-files.awk)는 다음과 같습니다.

/^total/ {next} # Skip the first line (which contains the total, of ls -l)

{
    if (name[$5] == "") {
    name[$5] = $NF
    print "# File of size", $5, "should be named", $NF
 } else {
    printf "mv '%s' '%s'\n", $NF, name[$5]
 }
}

명령줄(대상 폴더)에서 호출됩니다.

awk -f ~/rename-identical-files.awk <(ls -l /model-folder-path) <(ls -l) | sh 

문제는 다음과 같습니다엘에스(적어도) 파일 ​​이름의 공백 및 기타 문자에 대한 제한이 있는 명령입니다.

공백(및 아포스트로피) 문제를 방지하려면 어떤 코드를 작성해야 합니까?

답변1

예,ls출력을 안정적으로 구문 분석 하는 쉬운 방법은 없습니다..

여기에서 다음을 사용할 수 있습니다 zsh.

#! /bin/zsh -
zmodload zsh/stat || exit
typeset -A size_to_name
model_folder=${1?}

for f in $model_folder/*(ND.); do
  stat -LA size +size -- $f &&
    size_to_name[$size]=$f:t &&
    print -r "# File of size $size should be named ${(q)f:t}"
done

for f in *(ND.); do
  stat -LA size +size -- $f &&
    (($+size_to_name[$size])) &&
    [[ $f != $size_to_name[$size] ]] &&
    print -r mv -i -- ${(qq)f} ${(qq)size_to_name[$size]}
done

(다음으로 실행 that-script /model-folder-path)

파일 이름에 포함된 문자 또는 비문자에 관계없이 잘 작동합니다.

sh올바른지 확인한 후 파이프하십시오. 두 파일의 크기가 같은 경우는 확인하지 않습니다. 이 경우 어휘 순서의 마지막 항목이 선택됩니다( amodel_folder 의 크기가 모두 42인 경우 크기가 42인 모든 파일은 현재 폴더의 파일 z로 이름이 변경됩니다 ( 그러나 가능성은 있습니다). 다음 명령을 사용하는 첫 번째 파일) 두 번째)).z-i

답변2

두 디렉토리 사이의 동일한 파일을 식별하기 위해 체크섬을 사용하는 것이 더 정확할 것입니다. bash 4.3+를 사용하면 이를 수행할 수 있습니다.

getFiles() {
    local -n _files=$1
    local dir=${2:-.}
    cd "$dir"
    for file in *; do
        [[ -d $file ]] && continue
        read sum name < <(md5sum "$file")
        _files[$sum]="$file"
    done
    cd -
}

declare -A pwdFiles
getFiles pwdFiles

declare -A modelFiles
getFiles modelFiles /model-folder-path

for sum in "${!pwdFiles[@]}"; do
    if [[ -v modelFiles[$sum] ]]; then
        mv -v "${pwdFiles[$sum]}" "${modelFiles[$sum]}"
    fi
done

답변3

이전 이름 ​​바꾸기 오류를 수정하기 위한 일회성 작업이라고 가정하면(테스트되지 않음) 다음과 같은 간단한 diff의 문제점은 무엇입니까?

for newfile in *; do
    for oldpath in /model-folder-path/*; do
        if ! diff -q "$oldpath" "$newfile" >/dev/null; then
            oldfile=${oldpath##*/}
            if [[ "$oldfile" != "$newfile" ]]; then
                if [[ -f "$oldfile" ]]; then
                    echo "clash on $oldfile" >&2
                    exit 1
                fi
                mv -- "$newfile" "$oldfile"
            fi
        fi
    done
done

관련 정보