
以下のスクリプトは現在の^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
答え2
スクリプトの周りにループを置くことができます。だから:
for c in "^I" "^M"; do
for file; do
if grep "$c" "$file"; then
...
etc.
...
fi
done
done
答え3
私はこのPerl Oneライナーを好みます。 '\ cM'は制御M文字です。元のファイルは「.bak」拡張子でバックアップされます。この拡張はあなたが選ぶことができます。
perl -i.bak -pe 's/\cM//g;' file(s)
削除する文字タイプを使用する例。括弧内では、perlはcontrol-Iとcontrol-Mを見つけて削除します。しかし、まだ具体的にテストしていません。
perl -i.bak -pe 's/[\cM\cI]//g;' files(s)
答え4
使用について考えたことがありますか?
tr -d .....<characterlist>....
たとえば、印刷できない文字をすべて削除して別のファイルに入れます。
cat filename | tr -cd '[:print:]' >/tmp/x.out
アプリケーションに合わせて文字リストを変更します。tr
詳しくはマニュアルページをご覧ください。
正規表現の範囲が許容されるので、これも良いです。
echo '\001\002\003\004' | tr -d '[\001-\003]' | od -c