ファイルの文字を置き換える

ファイルの文字を置き換える

こんにちは、私は2つのシンボルを取り、最初のシンボルを2番目のシンボルに置き換えるスクリプトを書いています。スクリプトはそれをパラメータファイルとしても使用します。アイデアは、ファイルの最初の文字を2番目の文字に置き換えることです。スクリプトは次のとおりです。

char_src=$1
char_dest=$2
shift

for file
do
    while read -r line
    do
        line=${line//$char_src/$char_dest}
        echo "$line"
    done < "$file"
done

問題は正しい内容を印刷しますが、変更をファイルに保存しないことです。 done < "$file"

ベストアンサー1

まず、簡単な部分:シェルからファイルを1行ずつ読み込むのが遅いので、代わりにこれを使用できますtrman tr詳細より。

第二に、一時ファイルが必要です。ファイルを同時に読み書きすることはできません(どうせシェルでは不可能)。したがって、次のようにする必要があります。

tr -- "$1" "$2" <"$file" >"$file".tmp
mv -f -- "$file".tmp "$file"

明らかな質問は、tr何らかの理由で($1空の場合など)失敗するとどうなるかです。その後、$file.tmpまだ生成され(シェルが行を解析したときに生成されます)、$file置き換えられます。

したがって、より安全なアプローチは次のとおりです。

tr -- "$1" "$2" <"$file" >"$file".tmp && \
mv -f -- "$file".tmp "$file"

これ$fileで成功した場合にのみ交換されます。tr

しかし、周囲に別のファイル名があるとどうなりますか$file.tmp?まあ、それは扱われます。ここでは状況がさらに複雑になります。技術的に正しい方法は次のとおりです。

tmp="$( mktemp -t "${0##*/}"_"$$"_.XXXXXXXX )" && \
trap 'rm -f "$tmp"' EXIT HUP INT QUIT TERM || exit 1
tr -- "$1" "$2" <"$file" >"$tmp" && \
cat -- "$tmp" >"$file" && \
rm -f -- "$tmp"

これによりmktemp一時ファイルが生成されます。trapスクリプトが正常または異常終了すると、ファイルはクリーンアップされ、代わりにcat -- "$tmp" >"$file"権限が保持mv$fileれます。書き込み権限がないと$fileまだ失敗する可能性がありますが、一時ファイルは最終的に削除されます。

または、GNUにはsedファイルをその場で編集するオプションがあるので、次のことができます。

sed -i "s/$1/$2/g" "$file"

ただし、これはビューほど単純ではありません。$1またはforが特別な意味を持つ場合、上記の操作$2は失敗しますsed。したがって、まずエスケープする必要があります。

in=$(  printf '%s\n' "$1" | sed 's:[][\/.^$*]:\\&:g' )
out=$( printf '%s\n' "$2" | sed 's:[\/&]:\\&:g;$!s/$/\\/' )
sed -i "s/$in/$out/" "$file"

おすすめ記事