2017-05-06 224 views
4

我想將文本文件的前六個字符讀入一個字符串,並在該文件中用該字符串前面加上其他所有非空行。此類文件的一個例子是:sed中的命令替換

04/17 Walmart .toys $ 70 .cash $ -70 

Caltex .gas 20 $ .cheque $ -20 

McDonalds .burger 1 $ .cash $ -1 

每個條目,即:每一個非空行,需要一個日期,這對於簡單的數據錄入的原因一直只在第一行輸入。條目由一個或多個空行分隔。輸出應該是這樣的:

04/17 Walmart .toys $ 70 .cash $ -70 

04/17 Caltex .gas 20 $ .cheque $ -20 

04/17 McDonalds .burger 1 $ .cash $ -1 

我可以匹配的東西非空字符串像^[^@]+[ ]*.[ ]([^;{}:]+)[ ]*$,但我不知道如何真正落實,對非空行。

This Bash script外觀吸引了我,但我不知道該怎麼然後在開始插入我的字符串。

我也無法找到明確的答案,以我的堆棧溢出 問題。

我想它接受一個文件名的腳本:

read -n 6 date < $1 
sed 's/^/$(echo $date)/' | \ 
sed 's/^$(echo $date)\n//' | > $newName 

我能拿出前面加上空間的日期(例如字符串:'04/17「),每行,然後從沒有任何東西出現的每一行中刪除它們。

然而,似乎SED不接受命令替換:

sed: -e expression #1, char 10: unknown option to `s' 

回答

5

你應該能夠與一個sed命令來做到這一點:

read -rn 6 date < "$1" 
sed -E 's#^([a-zA-Z]+)#'"$date"' \1#g' "$1" > newfile 

捕獲組確保在插入日期之前,行上至少有一個字符。

編輯:基於修改你的問題:

newfile="output.txt" 
lineone=$(head -1 "$1"); 

read -rn 6 date <<< "$lineone" 
sed -E 's#^([a-zA-Z]+)#'"$date"' \1#g; 1s#^.*$#'"$lineone"'#' "$1" > "$newfile" 

既然你是不是做就地編輯,你可以做$日期插入,然後回去換出第一行,因爲它會結束兩個日期。有可能是「更好」的方式來做到這一點,如使用Perl,或失去第二sed命令,但至少應該給你一個基本的想法,雖然它是如何工作的?

結果(newfile中) :

04/17 Walmart .toys $ 70 .cash $ -70 

04/17 Caltex .gas 20 $ .cheque $ -20 

04/17 McDonalds .burger 1 $ .cash $ -1 

注:在sed一些版本的擴展正則表達式的選項可以 或者是-r-E

+0

這很奇怪,除了掛在我的GNU sed 4.2.1之外,它似乎沒有在這裏做任何事情。但我想我多多少少會看到你想要做的事情。 – HarryH

+0

@HarryH,它可以在* GNU sed v4.2.2 *上運行。 – agc

+0

GNU sed 4.2.1的聯機幫助頁未提及'-E'選項。我嘗試了'-r'選項,但仍然掛起。 – HarryH

2

被終止sed命令的斜線,分隔符更改爲其他:

"s#^#$(echo $date)#" 

你很可能這樣寫:

"s#^#$date#" 

但是請注意,這種方法一般是fr敏捷(正如你發現的那樣),因爲你不能把變量當作字符串。


根據更新問題上的示例,我建議使用單個awk命令來完成文本處理。像這樣的東西可以給你的輸出樣本:

$ cat file 
04/17 Walmart .toys $ 70 .cash $ -70 

Caltex .gas 20 $ .cheque $ -20 

McDonalds .burger 1 $ .cash $ -1 

$ awk 'NR==1{d=$1}NR>1&&NF>0{$0=d" "$0}1' file 
04/17 Walmart .toys $ 70 .cash $ -70 

04/17 Caltex .gas 20 $ .cheque $ -20 

04/17 McDonalds .burger 1 $ .cash $ -1 
+1

你說得對在這兩方面。非常感謝!但是,'read -n 6 date <$ 1'省略了第6個字符,即:空格,所以我不得不手動添加它。沒問題,但。然後就是#s#^ $ date#\ n#「'沒有做我想做的事情:只用一個空行代替行,這是可以理解的。任何想法如何獲得這種效果? – HarryH

+0

@HarryH:我不確定我是否理解這個需求......你能否更新這個問題以包含樣本輸入數據和該數據的預期輸出? – user000001

+0

我剛剛添加了輸入和期望的輸出樣本。 – HarryH

3

bash答案:

unset n 
while read -r x ; do 
    case "${#n}$x" in 6) ;; 6*) x="$n$x" ;; *) n="${x:0:6}" ;; esac 
    echo "$x" 
done <file> newfile 

輸出:

04/17 Walmart .toys $ 70 .cash $ -70 

04/17 Caltex .gas 20 $ .cheque $ -20 

04/17 McDonalds .burger 1 $ .cash $ -1 
+0

我沒有測試它,因爲我已經與我一起解決方案,但它看起來不錯。 – HarryH

4

使用Perl:

perl -plE 'if($.==1){$d=substr($_,0,6);next}elsif(/./){s/^/$d/}' file > new 

輸出

04/17 Walmart .toys $ 70 .cash $ -70 

04/17 Caltex .gas 20 $ .cheque $ -20 

04/17 McDonalds .burger 1 $ .cash $ -1 

或與備份相同的文件file.bak

perl -i.bak -plE 'if($.==1){$d=substr($_,0,6);next}elsif(/./){s/^/$d/}' file 

或者相同的文件沒有備份

perl -i -plE 'if($.==1){$d=substr($_,0,6);next}elsif(/./){s/^/$d/}' file 

或者,如果你不確定的日期的前導零,

perl -plE 'if($.==1){($d)=m|^(\d+/\d+\s)|;next}elsif(/./){s/^/$d/}' file 

將一號線的起點匹配任何digit(s)/digit(s) space

由於l'L'l在評論中提到,所以上面也將日期添加到僞空行(其中行只看起來像空),例如它至少包含一個空格。在這種情況下,代替的/./

  • 使用/\w/ - 因此,在前面加上日期僅含有至少一個單詞的字符線;
  • 或者使用/\S/ - 至少包含一個非空格字符

說明時:

perl -plE '     # Run the commands on every input line and print them. 
    if($. == 1) {    # If it is the 1st line 
     $d = substr($_, 0, 6); # take the first 6 characters and store it to $d 
     next     # And continue to the next line. 
    } 
    elsif(/\S/) {   # Else if the line contains any nonspace character 
     s/^/$d/    # add to the beginning the content of $d 
    } 
    ' file > new 
+1

非常好的答案,你有我的投票:) - 只有一個問題,但我可能會提及。如果空白行以空格開頭,那麼您最終會得到一個日期。 –

+0

@ l'l l - 是的,可能不是'/./'最好使用'/ \ w /'。感謝名單。 :) – jm666

+0

是的,我不得不改變我的也是,很好的答案,無論。 –