ファイルから複数の特殊文字を削除するには?

ファイルから複数の特殊文字を削除するには?

以下のスクリプトは現在の^M文字(Ctrl+V+M)を削除します。ちょっと冗長なようですが、^Iと今後見ることができる他の文字も追加する必要があります。

^I( ) を追加する簡単な方法はありますかCtrl+V+I?これは、約6ヶ月前に2日間のシェルプログラミングプロセスを受講した後、私が自分で書いた最初のスクリプトです。必要以上に時間がかかるかどうかわからないので、一般的なヒントも教えてくれてありがとう。

#!/bin/bash  

    echo "$# item(s) to review."
    question='Do you want to remove the ^M characters?'

    for file
    do
            if grep "^M" "$file" >> /dev/null 2> /dev/null
            then
                    echo "$file contains special characters"
                    echo $question
                    read answer
                            if    [[ "$answer" == [yY] ]]
                            then
                                    cat "$file" | sed "s/^M//" > "$file.safe"
                                    echo "Special characters have been removed and $file.safe has been created."
                            elif  [[ "$answer" == [yY][eE][sSaA]* ]]
                            then
                                    cat "$file" | sed "s/^M//" > "$file.safe"
                                    echo "Special characters have been removed and $file.safe has been created."
                            else
                                    echo "Special characters have NOT been removed."
                            fi
            elif [[ -d $file ]]
            then
                    echo "$file is a directory"
            else
                    echo "No special characters in $file"
            fi
    done

ベストアンサー1

確かに必要以上にずっと時間がかかりました。あなたに必要なものtr便利スクリプトには、引数として渡されたファイルに対して機能するループとリダイレクトが含まれます。

#!/bin/sh
for file do
  tr -d '\r\t' <"$file" >"$file.safe"
done

オプションを使用して指定された文字を削除-dしますtr。削除する文字は、オプションではなく最初の引数として一緒に渡されます。バックスラッシュエスケープを使用して、\n改行(^ J)、\rキャリッジリターン(^ M)、\tタブ(^ I)などの特殊文字を表すことができます。

ユーザーに尋ねるコードは、話すことができないためコピーしませんでした。とにかく、ディレクトリはリダイレクトエラーを引き起こし、ディレクトリを通常のファイルとして扱うなどの無意味な操作を実際に要求しないのが呼び出し側の仕事であるため、その部分もスキップされました。

元のファイルを置き換えるには、一時ファイルに書き込み、結果を所定の位置に移動します。

#!/bin/sh
for file do
  tmp="$(TMPDIR=$(dirname -- "$file") mktemp)"
  tr -d '\r\t' <"$file" >"$tmp" && mv -f -- "$tmp" "$file"
done

一時ファイル名は、mktempスクリプトをより強力にするように構成されています。ファイルを含むディレクトリへの書き込みアクセス権がある限り、既存のファイルを上書きする危険なしに機能します。他のデータを挿入しようとする他のユーザーがそのディレクトリに書き込むことができますが(参照資料の潜在的な問題/tmp)、安全です。

mvこのコマンドは呼び出しが成功した場合にのみ呼び出されるため、tr失敗してもデータが失われる危険はありません(ディスクがいっぱいになった場合など)。tr

ファイルを特殊文字を含まない同じ新しいファイルに置き換えることを防ぐには、次の2つの方法があります。

  • 特殊文字を最初に確認できます。これを行う方法はいくつかあります。 1つの方法は、特殊文字を除くすべての文字を削除し、結果の文字数を数えることです。最適化として、head -c 1特殊文字が上部近くにある場合は、ファイル全体を確認する必要がないようにパイプします。これを行うと、何もしない場合はカウントは0、それ以外の場合は1です。

    if [ "$(tr -dc '\r\t' <"$file" | head -c 1 | wc -c)" -ne 0 ]; then
      tr -d '\r\t' <"$file" >"$tmp" && mv -f -- "$tmp" "$file"
    fi
    
  • 変換後、元のバージョンと同じであることを確認できます。通常、ファイルが既に希望の状態にある場合は、速度が遅くなる可能性があります。一方、この手法は、ファイルが必要な状態であるかどうかを判断するのが簡単ではない状況に適しています。

    tr -d '\r\t' <"$file" >"$tmp" &&
    if cmp -s "$tmp" "$file"; then
      rm -- "$tmp"
    else
      mv -f -- "$tmp" "$file"
    fi
    

おすすめ記事