こんにちは、私は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行ずつ読み込むのが遅いので、代わりにこれを使用できますtr
。man 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"