awkスクリプトにおけるlsの空白とアポストロフィの問題の防止

awkスクリプトにおけるlsの空白とアポストロフィの問題の防止

2つの(ローカル)デバイスに同じファイルがたくさんあり、1つのデバイス(A)の一部のファイル名のみが変更されました。デバイスAの新しい名前に基づいて、異なるデバイス(B)で同じファイルの名前を変更し、最終的に同じファイルと名前ファイルを持つ次の方法を見つけました。いかなる内容も削除またはコピーしないでください。しかし、ただ名前変更

実際、私は興味深い答えを見つけました。ここHai Vuで(2回目の回答)

スクリプト働くしかし、2つのことがあります質問:

  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

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

関連情報