2017-08-14 84 views
0

我有一個非常特殊的需求,爲此我一直試圖解決,但沒有成功。只有在條件適用的情況下刪除非ASCII字符,在bash中

我有一個日誌,它是由一個tcp/ip套接字轉儲創建的......它將十六進制轉換爲ASCII,但自然也有一些特殊字符。

我已經設法刪除它們,但是我目前遇到了一些困難:有時,發送了一個0x0A,這與我的應用程序混淆了......我試圖將其刪除,但它也刪除了在該行的末尾有效的0x0A ...

基本上,我有,在日誌文件:

08-14-2017 10:00:00 String={Teste String} 
08-14-2017 10:00:00 String={ 
Teste String2} 
08-14-2017 10:00:00 String={ 
Teste String3} 
08-14-2017 10:00:00 String={Teste String4} 

我想最終結果爲

08-14-2017 10:00:00 String={Teste String} 
08-14-2017 10:00:00 String={Teste String2} 
08-14-2017 10:00:00 String={Teste String3} 
08-14-2017 10:00:00 String={Teste String4} 

中的人物總是之間{},所以}之後的每個0x0A都是有效的,但裏面不是。

我試過的每一個命令要麼刪除所有的0x0A,要麼根本不工作。

我試過的東西

sed 's/^[^}]*}//' 
sed 's/\x0A$//' 

有什麼想法?

+0

你在ASCII文本或十六進制上應用sed命令嗎? – pchaigno

+0

關於ASCII文本... –

回答

1

這當然是可能的SED,但它更容易閱讀和理解AWK:

awk 'BEGIN{ OFS=FS="{"; ORS=RS="}" } { sub(/[^[:print:]]/,"",$2) } 1' input.txt 

這是什麼呢?

  • 首先,我們設定的輸入和輸出字段分隔符來{,我們的輸入和輸出的記錄分隔符來}。這讓我們可以預測地將括號內的文字作爲特定的字段(至少根據您的樣本數據)。
  • 接下來,我們用一個空字符串替換字段#2中的所有非打印字符,從而消除換行符,退格等。
  • 最後,我們使用awk速記打印行。
0

使用sed

的Linux:

$ sed -r ':a;N;$!ba;s/(\{[^}]*)\\n([^{]*\})/\1\2/g' file 
08-14-2017 10:00:00 String={Teste String} 
08-14-2017 10:00:00 String={Teste String2} 
08-14-2017 10:00:00 String={Teste String3} 
08-14-2017 10:00:00 String={Teste String4} 

的FreeBSD和MacOS:

sed -e ':a' -e 'N;$!ba' -e 's/(\{[^}]*)\\n([^{]*\})/\1\2/g' file 

說明

-e ':a' -e 'N;$!ba'允許我們在sed的每次迭代中考慮當前行和下一行。有關詳細信息,請參閱this SO answer

(\{[^}]*)確保有一個開口支架,緊隨其後的是一個開口支架。

([^{]*\})正好相反。

+0

在我的FreeBSD或macOS中不起作用。這個GNU-sed是特定的嗎? – ghoti

+0

是的,我會更新。 – pchaigno

+0

當你分割它的時候:'sed -E -e':a'-e'N; $!ba'-e's /(\ {[^}] *)\ n([^ {] * \ })/ \ 1 \ 2/g'' ..非GNU sed似乎希望標籤後面不要加分號。 – ghoti

0

的Perl:

$ perl -0777 -pe 's/({[^}]*)\x0A([^}]*})/\1\2/g' file 
08-14-2017 10:00:00 String={Teste String} 
08-14-2017 10:00:00 String={Teste String2} 
08-14-2017 10:00:00 String={Teste String3} 
08-14-2017 10:00:00 String={Teste String4} 

純擊(基於anubhava的AWK):

while IFS="\n" read -r line; do 
    le="" 
    [[ $line =~ \} ]] && le=$'\n' 
    printf "%s%s" "$line" "$le" 
done <file 
3

另一個簡單awk

awk '{printf "%s%s", $0, (/}/ ? ORS : "")}' file 

08-14-2017 10:00:00 String={Teste String} 
08-14-2017 10:00:00 String={Teste String2} 
08-14-2017 10:00:00 String={Teste String3} 
08-14-2017 10:00:00 String={Teste String4} 

awk命令檢查存在在一行中,然後只打印換行符,否則打印記錄不換行。

+1

這太棒了。 – dawg

+1

是的,它應該是'ORS' :) – anubhava

1

隨着GNU AWK多焦RS我們就可以隔離每個{...}串並刪除新行內它:

$ awk -v RS='{[^}]+}' '{ORS=gensub(/\n/,"","g",RT)}1' file 
08-14-2017 10:00:00 String={Teste String} 
08-14-2017 10:00:00 String={Teste String2} 
08-14-2017 10:00:00 String={Teste String3} 
08-14-2017 10:00:00 String={Teste String4} 

對於這個特定的情況下,其他的awk答案會工作得很好,上面只是一個更通用的解決方案來隔離分隔字符串,然後在其上執行操作(如在此情況下刪除字符)。

相關問題