2016-01-06 189 views
0

OSX上的sed有一些怪癖。該資源(http://nlfiedler.github.io/2010/12/05/newlines-in-sed-on-mac.html)包含有關如何空格轉換成一個換行符信息:OSX sed換行符 - 爲什麼將空格轉換爲換行符,但換行符不會轉換爲空格

echo 'foo bar baz quux' | sed -e 's/ /\'$'\n/g' 

OR(@ ghoti的建議,這也使其更易於閱讀):

echo 'foo bar baz quux' | sed -e $'s/ /\\\n/g' 

然而,當我嘗試反向 - 換行轉換到空白,這是行不通的:

echo -e "foo\nbar" | sed -e 's/\'$'\n/ /g' 

的只是改變\n更簡單的方法行不通eithe R:

echo -e "foo\nbar" | sed -e 's/\n/ /g' 

有一個相關的答案在這裏:https://superuser.com/questions/307165/newlines-in-sed-on-mac-os-x,由斯皮夫了詳細的解答(右頁面結束),但是應用相同的邏輯並沒有解決問題。

這裏是一個沒有在OSX工作(通過http://www.benjiegillam.com/2011/09/using-sed-to-replace-newlines/)的方式:

sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' 

不過,我仍然好奇,爲什麼扭轉了原來的做法是行不通的。

更新:這裏是如何使它與兩行的工作(該解決方案是使用N嵌入換行符):

echo -e "foo\nbar\n" | sed -e 'N;s/\n/ /g' 

的替代解決方案(見@ghoti詳細解釋完整的答案) :

echo -e "foo\nbar\n" | sed -n '1h;2,$H;${;x;s/\n/ /gp;}' 

然而,這種解決方案似乎是一點點慢於一個問題中陳述建議(這些命令的事項記順序,因此它可能是有意義的嘗試以不同的順序測試它們):

time seq 10000 | sed -n '1h;2,$H;${;x;s/\n/ /gp;}' > /dev/null 

time seq 10000 | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' > /dev/null 
+0

用三行輸入嘗試更新的解決方案。並查看下面的答案。 :) – ghoti

+0

另外,如果你沒有看到這個,你的第一個例子''/'\'''\ n/g''實際上依賴於shell擴展。 (請查看友好的鄰居bash手冊頁的QUOTING部分。)它將在bash和其他一些shell中工作,但不是通用的(或POSIX)。您可以通過對整個表達式使用相同的引用樣式來使其更清晰或更易於閱讀:'sed -e $'s// \\\ n/g''。 – ghoti

回答

1

您的問題似乎是「爲什麼不將原始方法(將空格轉換爲換行符)的工作原理相反?」。

在sed中,換行符比行的一部分更像是一個記錄分隔符。考慮$,即模式空間末尾的null,位於該行的最後一個字符之後,並且不是每行的換行符。

使用換行符的Sed命令(如HN甚至s)在換行符作爲記錄分隔符的範圍之外。您要替換的記錄位於換行符之間。

爲了替代換行符,那麼,你需要把它裏面的模式空間,使用NH

因此,這裏是一個選項。

printf 'foo\nbar\nbaz\n' | sed -n '1h;2,$H;${;x;s/\n/ /gp;}' 

的想法是,我們將我們所有的行追加到保持緩衝器,然後在文件的結尾,將保持緩衝器回用於替代模式空間和空格替換所有的換行立刻。

1h;2,$H構造避免了在輸出開始時出現空白,這是由於在每行數據前附加了換行符H

+0

謝謝!它可以工作,但是我想知道'$ {}'是否會給性能帶來額外的壓力? – econ

+0

我懷疑如果有性能影響,它將會在非常大的文件上,因爲使用此解決方案,sed需要將所有輸入數據存儲在內存中(保持緩衝區),直到它到達文件末尾。如果你想要更精簡的東西,也許'awk'{printf(「%s」,$ 0)}''將會是更好的選擇,或者'tr'\ n''''如果這足夠滿足你的需求。但是這又解決了。你的問題的答案是上面的部分,關於換行符作爲分隔符而不是字符串的一部分。 – ghoti

1

的GNU手冊頁sed包括:

正則表達式

POSIX.2 BREs裏面應該支持,但他們也不是完全因爲性能問題。正則表達式中的\n序列與換行符匹配,並且類似地爲\a\t和其他序列。

的Mac OS X中的sed手冊頁包括:

桑達正則表達式

sed使用,默認情況下,正則表達式,是基本的正則表達式(BREs裏面,見請參閱re_format (7)以獲取更多信息),但如果給出-E標誌,則可以使用擴展(現代)正則表達式。此外,sed有以下兩個補充的正則表達式:

  1. 在上下文地址,比反斜槓(\)或換行字符以外的任何字符可以被用於分隔正則表達式。此外,在分隔字符之前放置反斜槓字符會導致字符被逐字處理。例如,在上下文地址\xabc\xdefx中,RE分隔符是x,第二個x代表自己,因此正則表達式是abcxdef

  2. 轉義序列\n與嵌入模式空間的換行符匹配。但是,您不能在地址或替代命令中使用文字換行符。

什麼這些不說,但似乎是的情況下,是在s/regex/new/命令時,regex部分是一個正則表達式,但new部分是沒有的。在替換材質中,您必須使用\,然後換行以嵌入換行符。在搜索材料(regex)中,您可以使用\n

還請注意sed在線工作。默認情況下,除了正則表達式元字符$之外,模式空間末尾的換行符幾乎是不可比擬的;你不能通過匹配它來簡單地刪除該新行。但是,您可以在模式空間中結束多行,然後您可以將嵌入換行符與\n模式匹配。

+0

謝謝,這是我第一次嘗試,並沒有奏效。 'sed -e's/\ n// g''問題陳述中的工作代碼在搜索材料中也包含'\ n',但該部分奇怪地起作用(當它在文件的明確讀取之前)。 – econ

+0

有一個問題,'sed'是基於行的,而最後一個換行符「不計數」。你不能只從行尾刪除換行符;您可以刪除嵌入的換行符,因爲您一直在使用嵌入換行符的命令(例如,「N」和「H」)。 –

+0

它看起來像我不小心一直在引用GNU'sed'手冊。我的錯。我希望我明白它是怎麼出錯的 - 手冊被大量地塞入('〜/ oss/share/man/man1/sed.1'),但即使MANPATH未設置,「man」也會設法找到它。哎呀!幸運的是,我不認爲我對手冊的評論是不準確的 - 正如我引用的內容不是我認爲我引用的那樣。當我研究出如何洗腦時,我會更新信息。 –

0

一些替代品,我傾向於在受到OSX sed特性阻礙時回落,是trperl

echo -e "foo\nbar" | tr '\n' ' ' 
foo bar 

echo -e "foo\nbar" | perl -pe 's/\n/ /' 
foo bar 
+0

謝謝,tr非常方便。對於這個問題,我非常好奇OSX的sed行爲,但是你的回答可以幫助尋找任何解決方案的人。 – econ

+0

@ ghoti我同意,但它是有針對性的和建設性的 - 只是在評論中表達一下有點尷尬:-) –