2013-12-10 36 views
0

我已經成功地寫入以下功能:發現的print0選項重新實現在bash和awk(perl的)

function print0(){ 
    stdin=$(cat); 
    echo "$stdin" | awk 'BEGIN {ORS="\000";}; { print $0}'; 
} 

它可以作爲一個-print0論點find命令,但基本上都是針對通過它的輸出到該功能的任何命令。這對xargs -0很有用。然後我意識到,與此功能相反也是有用的。我曾嘗試以下操作:

function read0(){ 
    stdin=$(cat); 
    echo "$stdin" | awk 'BEGIN {RS="\000"; ORS="\n";}; {print $0}'; 

    # EQUIVALENTS: 
    # echo "$stdin" | perl -nle '@a=join("\n", split(/\000/, $_)); print "@a"' 
    # echo "$stdin" | perl -nle '$\="\n"; @a=split(/\000/, $_); foreach (@a){print $_;}' 
} 

但它沒有工作,有趣的是,當我嘗試了命令(AWK或Perl),它的工作就像一個魅力:

# WORKING 
ls | print0 | awk 'BEGIN {RS="\000"; ORS="\n";}; {print $0}' 
ls | print0 | perl -nle '@a=join("\n", split(/\000/, $_)); print "@a"' 
ls | print0 | perl -nle '$\="\n"; @a=split(/\000/, $_); foreach (@a){print $_;}' 


# DOES NOT WORKING 
ls | print0 | read0 

我在做什麼錯?我假設的東西是錯誤通過以下命令處理空字符:stdin=$(cat);

編輯: 謝謝大家,得出的結論是bash的變量不能持有空值。 PS:提到的命令就像我知道的將NULL轉換成換行符一樣,反之亦然沒有理性的原因。

+0

+1有趣。雖然幫不了你。 – 2013-12-10 19:43:20

+0

shell在內部使用C字符串,C使用'\ 0'作爲字符串終止符。所以你不能把它當作字符串中的一個字符,它只會結束它。 – Barmar

回答

1

正如其他答案/評論提到的那樣,您不能在空字符串變量中放置空字符。但是,如果你能擺脫的變量,只是處理的管/流中的數據,那麼你可以通過就好傳遞空字符:

 
function print0() { 
    awk 'BEGIN {ORS="\000";}; {print $0}'; 
} 

function read0() { 
    awk 'BEGIN {RS="\000"; ORS="\n";}; {print $0}'; 
} 
 
[email protected]:~/dir$ ls -1 
file one 
file_two 
[email protected]:~/dir$ ls | print0 | read0 
file one 
file_two 
[email protected]:~/dir$ 

而且以這種方式使用ls是危險的,因爲它將不適用於包含換行符的文件名。據我所知,find方式編程方式獲取目錄中的文件列表,當奇數字符出現在文件名。


更新:

這裏的另一種方式編程獲取的文件列表中的目錄,當奇怪的字符出現在文件名中,不使用find(或有缺陷的ls)。我們可以使用* glob將目錄中的所有文件列表轉換爲bash數組。然後,我們打印出數組的每個成員,使用1個字符的/ dev /零作爲分隔符:

#!/bin/bash 

shopt -s nullglob 
shopt -s dotglob # display .files as well 

dirarray=(*) 

for ((i = 0 ; i < ${#dirarray[@]}; i++)); do 
    [ "$i" != "0" ] && head -c1 /dev/zero 
    printf "${dirarray[$i]}" 
done 
+0

我認爲任何awk上的「\ 0」和「\ 000」應該是相同的 - 至少,它們在我碰巧能夠訪問的三個awk上 - 但是將'ORS'設置爲'NUL',而不管你怎麼做,在'mawk'或原始awk代碼的當前版本上實際上並不「工作」。你係統上的awk是什麼? – rici

+0

@rici - 你是對的 - 「\ 0」和「\ 000」似乎現在是相同的 - 我一定是做錯了什麼。我的Ubuntu 12.04上的'awk'和'gawk'都是「GNU Awk 3.1.8」。 –

+1

數組的東西可以簡化爲'printf'%s \ 0「」$ {dirarray [@]}「'。這將打印一個尾隨的空值,但我認爲這就是你通常想要的。如果你想要的只是模擬'find ... -print0',你可以不使用數組,只是說'printf'%s \ 0「*'。 – user2719058

2

我要說的是,您的實現可以簡化爲

function print0 { tr '\n' '\0'; } 
function read0 { tr '\0' '\n'; } 

其工作方式你想。

但是,它沒有增加任何值;你只需從新行分隔記錄切換到NUL分隔記錄,反之亦然,而find ... -print0可以處理多行文件名。你的想法並不能解決這個問題。

您的問題的實際視圖 - 如何在bash中處理嵌入NUL字符的字符串 - 已在SO:assign string containing null-character (\0) to a variable in bash上進行了討論。底線是,你必須逃避它們。除此之外,zsh支持嵌入NUL字符,但顯然沒有其他shell。

關於處理NUL字符的read shell內置函數有一個related discussion on bug-bash,您可能會感興趣。