我想将文本文件的前六个字符读入一个字符串,并在该文件中使用该字符串添加其他所有非空行。这种文件的一个例子可能是:
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
我可以将非空字符串与^[^@]+[ ]*.[ ]([^;{}:]+)[ ]*$之类的字符匹配,但我不知道如何为非空白行实际实现该字符串。
This Bash script对我很有吸引力,但我不知道如何在开始时插入我的字符串。
我也无法在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'
答案 0 :(得分: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"
由于您没有进行就地编辑,您可以执行$ date插入,然后返回并换出第一行,因为它最终会有两个日期。可能有“更好”的方法来执行此操作,例如使用Perl
或丢失第二个sed
命令,尽管这至少应该为您提供一个基本的想法,但它是如何工作的......
结果(新文件):
04/17 Walmart .toys $ 70 .cash $ -70
04/17 Caltex .gas 20 $ .cheque $ -20
04/17 McDonalds .burger 1 $ .cash $ -1
注意:在某些版本的
sed
中,扩展正则表达式的选项可以 可以是-r
或-E
。
答案 1 :(得分: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
答案 2 :(得分:3)
纯(like : shipping_skudetails.itemWeight copied into shyplite.width)
回答:
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
答案 3 :(得分:2)
斜杠正在终止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