[英]Command substitution in sed
我想將一個文本文件的前六個字符讀入一個字符串,並在該文件中使用該字符串添加其他所有非空行。 這種文件的一個例子可能是:
04/17 Walmart .toys $ 70 .cash $ -70
Caltex .gas 20 $ .cheque $ -20
McDonalds .burger 1 $ .cash $ -1
每個條目,即:每個非空行,都需要一個日期,出於簡單數據輸入的原因,該日期僅在第一行輸入。 條目由1個或多個空行分隔。 輸出看起來像這樣:
04/17 Walmart .toys $ 70 .cash $ -70
04/17 Caltex .gas 20 $ .cheque $ -20
04/17 McDonalds .burger 1 $ .cash $ -1
我可以將非空字符串與^ [^ @] + [] *之類的東西相匹配。 [] ([^; {}:] +)[] * $ ,但我不知道如何為非空行實際實現。
這個Bash腳本對我很有吸引力,但我不知道如何在開始時插入我的字符串。
我也找不到Stack Overflow問題的直接答案。
我嘗試了一個接受文件名的腳本:
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'
您應該可以使用一個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"
由於您沒有進行就地編輯,您可以執行$ date插入,然后返回並換出第一行,因為它最終會有兩個日期。 可能有“更好”的方法來執行此操作,例如使用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
。
使用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'升在評論中提及,上述增加了偽空行太(其中線不僅看起來類似空)例如,它至少包含一個空格的日期。 在這種情況下,而不是/./
:
/\\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
純粹的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
斜杠正在終止sed命令,將分隔符更改為其他內容:
"s#^#$(echo $date)#"
你也可以這樣寫:
"s#^#$date#"
但請注意,這種方法通常很脆弱(正如您所發現的那樣),因為您無法將變量視為文字字符串。
基於更新問題的示例,我建議使用單個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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.