私は自分のサーバー用のシェルスクリプトを書いています。これは、FreeBSDを実行する共有ホスティングです。また、Linuxを実行しているPCでローカルにテストできるようにしたいと考えています。したがって、私はそれらを移植可能な方法で書き込もうとしていますが、sed
ではそれを行う方法がありません。
私のウェブサイトの一部は生成された静的HTMLファイルを使用しており、このsed行は各再生成後に正しいDOCTYPEを挿入します:
sed -i '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
LinuxではGNU sed
と連動しますが、FreeBSD sed
は-i
オプションの後にある最初の引数がバックアップコピーの拡張であると想定しています。これはそれがどのように見えるか:
sed -i '' '1s/^/<!DOCTYPE html> \n/' ${file_name.html}
ただし、GNU sed
は、式が-i
の直後に続くことを期待します。(また、改行処理の修正が必要ですが、すでに回答されています ここ )
もちろん、この変更をスクリプトのサーバーコピーに含めることはできますが、バージョン管理にVCSを使用するのは面倒です。完全に移植可能な方法でsedを使用してこれを達成する方法はありますか?
GNU sedは-i
の後にオプションの拡張子を受け入れます。拡張子は、間にスペースを入れずに同じ引数にある必要があります。この構文は、BSD sedでも機能します。
sed -i.bak -e '…' SOMEFILE
BSDでは、-i
は複数の入力ファイルがある場合の動作も変更することに注意してください。これらは独立して処理されます(たとえば、$
は各ファイルの最後の行と一致します)。また、これはBusyBoxでは機能しません。
バックアップファイルを使用したくない場合は、使用可能なsedのバージョンを確認できます。
case $(sed --help 2>&1) in
*GNU*) set sed -i;;
*) set sed -i '';;
esac
"$@" -e '…' "$file"
または、位置パラメータを壊さないようにするには、関数を定義します。
case $(sed --help 2>&1) in
*GNU*) sed_i () { sed -i "$@"; };;
*) sed_i () { sed -i '' "$@"; };;
esac
sed_i -e '…' "$file"
気になりたくない場合は、Perlを使用してください。
Perl -i -pe '…' "$file"
移植可能なスクリプトを作成する場合は、-i
を使用しないでください。POSIXにはありません。 sedが内部で行うことを手動で実行します。これは、あと1行のコードです。
sed -e '…' "$file" >"$file.new"
mv -- "$file.new" "$file"
sed
を素敵にプレイさせるトリックが見つからない場合は、次の方法を試してみてください:
-i
は使用しないでください。
sed '1s/^/<!DOCTYPE html> \n/' "${file_name.html}" > "${file_name.html}.tmp" &&
mv "${file_name.html}.tmp" "${file_name.html}"
Perlを使用する
Perl -i -pe 'print "<!DOCTYPE html> \n" if $.==1;' "${file_name.html}"
いつでもed
を使用して、既存のファイルの前に行を追加できます。
$ printf '0a\n<!DOCTYPE html>\n.\nw\n' | ed my.html
<!DOCTYPE html>
の周りのビットは、ed
へのコマンドであり、その行をファイルmy.html
に追加するように指示します。
sed
のこのコマンドも使用できると思います。
$ sed -i '1i<!DOCTYPE html>\n` testfile.csv
手動で何をすることもできますPerl -i
は内部で行います。
{ rm -f file && { echo '<!DOCTYPE html>'; cat; } > file;} < file
お気に入り Perl -i
、バックアップはありません。ここに記載されているほとんどのソリューションと同様に、ファイルの権限と所有権に影響を与え、シンボリックリンクを通常のファイルに変える可能性があることに注意してください。
と:
sed '1i\
<!DOCTYPE html>' file 1<> file
sed
はファイル自体を上書きするため、所有権、権限、シンボリックリンクには影響しません。これは、GNU sed
で機能します。sed
は、file
コマンドで上書きする前に、i
(私の場合は4k)からデータでいっぱいのバッファーを読み取ります。ファイルがsed
もその出力をバッファリングするという事実を除いて、4k以上。
基本的にsed
は、読み取りと書き込みのために4kのブロックで機能します。挿入する行が4kより小さい場合、sed
はまだ読み取っていないブロックを上書きすることはありません。
私はそれを当てにしません。
FreeBSD sed は、Mac OS Xでも使用され、-e
スイッチの後に-i
オプションが必要です。
言い換えれば、sed -i -e ...
はFreeBSDとGNU sed
の両方で機能するはずです。
より一般的には、FreeBSD sed -i
の後にバックアップ拡張機能を省略するには、コマンドの解析中にFreeBSD sed
の一部の混乱を避けるために、-i
に続く明示的なsed
オプションまたはスイッチが必要です。 -行引数。
(ただし、sed
インプレースファイル編集はファイルのiノードの変更につながることに注意してください。ファイルの "インプレース"編集 を参照してください)。
(一般的なヒントとして、最近のバージョンのFreeBSD sed
には-r
スイッチがあり、GNU sed
)との互換性が向上しています)。
echo a > testfile.txt
ls -li testfile.txt
#gsed -i -e 's/a/A/' testfile.txt
#bsdsed -i 's/a/A/' testfile.txt # does not work
bsdsed -i -e 's/a/A/' testfile.txt
ls -li testfile.txt
cat testfile.txt
VimはExモードで使用できます。
ex -sc '1i|<!DOCTYPE html>' -cx file
1
最初の行を選択
i
テキストと改行を挿入
x
保存して閉じる
または、コメントのように、プレーンな古い standardex
:
printf '%s\n' 1i '<!DOCTYPE html>' . x | ex file
競合状態を可能な限り回避しながら、単一のファイルに対してsed -i
を移植可能にエミュレートするには、次のようにします。
sed 'script' <<FILE >file
$(cat file)
FILE
ちなみに、これはsed -i
が引き起こす可能性のある問題も処理します。ディレクトリとファイルの権限に応じて、sed -i
は、ユーザーが編集権限を持たないファイルを上書きできるようにする可能性があります。
次のようなバックアップも実行できます。
sed 'script' <<FILE >file
$(tee file.old <file)
FILE