web-dev-qa-db-ja.com

curlコマンドの出力をファイルの行番号に挿入します

いくつかのことを自動化するためのスクリプトに取り組んでいます。 sedコマンドを実行してcurlの出力をファイルの行番号に挿入する際に問題が発生しました

コマンドの複数のバリエーションを試しましたが、sedからエラーが発生するだけです。

sed "49i/.*/\"$(curl URL)\"/" file.php
sed: -e expression #1, char 105: extra characters after command

どんなアイデアもありがとう

1
AcidzDesigns

_curl URL_の出力($()trailingnewline(s)を削除した後)には、おそらく改行文字が含まれています。これは、sedのスクリプトであると想定されるコマンドライン引数に挿入されます。ツールはコードを解析し、_49i_の後に改行を検出し、スクリプト内の次のコマンドとして続くものを解釈します。

エラーが発生しました。さらに悪いことに、curlからの出力が構文的に有効なsedコードをスクリプトに挿入する可能性があります。あなたはこれを望まない。

$(curl URL | tr -d '\n')を使用してall改行を削除しても、curlの出力はそのまま挿入されない場合があります(たとえば、円記号には特別な意味があります)。

解決策:curlに一時ファイルに書き込んでから、sedにファイルを出力させます。ファイルの内容はコードとして解釈されません。

curlからの出力を、49行目の元のコンテンツの前に表示したいようです。その場合は、48行目でrを使用する必要があります(rは後で出力するためにテキストをスケジュールするため)。

コードは_/.*/"curl output here"/_の形式で何かを挿入しようとします。これがsの構文をiで使用しようとしたことによるアーティファクトではない場合は、これらの追加のフラグメントもファイルに書き込む必要があります。

通常、_curl -o_を使用して、curlをファイルに書き込むことができます。この場合、末尾の改行が削除されないため、希望どおりにならない可能性があります(使用した$()は削除します)。だからたぶんこれ:

_tmpfile="$(mktemp)"
printf '/.*/"%s"/' "$(curl URL)" >"$tmpfile"
sed "48 r $tmpfile" file.php
rm "$tmpfile"
_

一般に、curlからの出力が長すぎると失敗することに注意してください。より堅牢な解決策は、curlをファイルに直接出力し、次のステップで 改行を末尾から削除する にすることです。

一時ファイルへのパスに改行を含めることはできません。改行が含まれている場合、パスの一部がsedコマンドとして解釈され、無効である可能性があります。あなたが経験したものと幾分似ているバグ。 _$TMPDIR_に改行が含まれていない限り、パスに改行は含まれません(ただし、実際には改行を含めるべきではありません)。問題が発生した場合(たとえば、mktempが利用できない場合)、一時的な場所を選択する別の方法を使用します。最も基本的な設定では、場所がハードコーディングされている場合があります(ただし、スクリプトの複数のインスタンスを同時に実行しないでください)。

2

sedi...\nコマンドの構文はs/.../.../...と同じではありません。これが、ここでの主な問題だと思います。 curl出力に改行が含まれている可能性があり、最終的にiコマンドが終了するという事実に加えて。


s/find/replace/findを検索し、それをreplaceと交換します

以下の例では、正規表現3に一致するテキストがスワップアウトされています。

$ echo -e "1\n2\n3\n4\n5" | sed 's/3/new line/'
1
2
new line
4
5

inew lineは、一致した行の前にnew lineを挿入します

以下の例では、アドレスまたは一致を指定していないため、every入力行の前にnew lineが挿入されています。

$ echo -e "1\n2\n3\n4\n5" | sed 'inew line'
new line
1
new line
2
new line
3
new line
4
new line
5

あなたがしようとしていることは、与えられた行番号(別名 "address")に新しい行を挿入することであるように見えます。これはこのように達成することができます。 iコマンドは改行(または文字列の終わり)で終了することに注意してください-new lineは前に挿入され、3行目を置き換えません。

$ echo -e "1\n2\n3\n4\n5" | sed '3inew line'
1
2
new line
3
4
5

curlの出力を使用していると、これに改行が含まれていることに気付くかもしれません。これにより、iコマンドが終了します...したがって、変換する必要があります。 curlの出力を1行にするか、最初の行のみを含めます。headxxdなどのツールを使用して次のことができます。

$ curl "${url}"
line one
line two
line three

最初の行のみを保持します。

$ new_line="$(curl -s "${url}" | head -n 1)"
$ echo -e "1\n2\n3\n4\n5" | sed '3i'"${new_line}"
1
2
line one
3
4
5

すべての改行(\r\nおよび\n)をリテラル文字\nにエスケープします。 sedは、これらを改行に変換し直します。

$ new_line="$(curl -s "${url}" | xxd -p | sed -re 's/(0d)?0a/5c6e/g;s/5c6e$//' | xxd -r -p)"
$ echo -e "1\n2\n3\n4\n5" | sed '3i'"${new_line}"
1
2
line one
line two
line three
3
4
5

すべての改行(\r\nおよび\n)をリテラル文字\\nにエスケープします。次に、sedはこれらをリテラル文字\nに変換し、1行が挿入されます。

$ new_line="$(curl -s "${url}" | xxd -p | sed -re 's/(0d)?0a/5c5c6e/g;s/5c5c6e$//' | xxd -r -p)"
$ echo -e "1\n2\n3\n4\n5" | sed '3i'"${new_line}"
1
2
line one\nline two\nline three
3
4
5

これは、それが可能であることを示していますが、より良いアプローチは、このようにheadcurl、およびtailを使用してファイルを再構築することです。 ..将来的にはもっと読みやすくなるでしょう:

$ echo -e "1\n2\n3\n4\n5" > "${file}"
$ tmpfile="$(mktemp)"
$ ( head -n 2 < "${file}"; curl "${url}"; tail -n +3 < "${file}" ) > "${tmpfile}"
$ mv "${tmpfile}" "${file}"
$ cat "${file}"
1
2
line one
line two
line three
3
4
5
1
Attie