从文件中删除前两行、后两行和空格,并在每行添加引号,并在 shell 脚本中用逗号替换换行符



我必须输入.txt需要由shell脚本格式化的文件

,条件如下
  1. 删除前两行和 最后两行
  2. 删除每个中的所有空格 行(每行有两个空格,位于 开头和结尾一个空格)
  3. 每行应在单个行内 引号(' ')
  4. 最后将换行符($) 替换为 逗号。

(原文)输入.txt

sql
--------
Abce
Bca
Efr
-------
Row (3)

所需的输出文件

输出.txt

'Abce','Bca','Efr'

我试过使用以下命令

Sed -i 1,2d input.txt > input.txt
Sed "$(( $(wc -l <input.txt) -2+1)), $ d" Input.txt > input.txt
Sed ':a;N;$!ba;s/n/, /g' input.txt > output.txt

但是我得到空白输出.txt

请您尝试以下操作:

mapfile -t ary < <(tail -n +3 input.txt | head -n -2 | sed -E "s/^[[:blank:]]*/'/; s/[[:blank:]]*$/'/")
(IFS=,; echo "${ary[*]}")
tail -n +3输出第 3 行之后的行
  • (包括第 3 行)。
  • head -n -2输出不包括最后 2 行的行。
  • sed -E "s/^[[:blank:]]*/'/"删除前导空格和前置 单引号。
  • 同样,sed 命令"s/[[:blank:]]*$/'/"删除尾随 空格并附加单个引号。
  • 语法 <(命令 ..) 是一个进程替换和 括号内命令的输出将馈送到mapfile通过重定向。
  • mapfile -t ary从标准输入读取到数组中的行 名为ary的变量。
  • echo "${ary[*]}"扩展到单个字符串,其内容为 数组aryIFS的值分隔,该值刚刚赋值 到逗号。
  • IFS的分配和阵列扩展用 要在子外壳中执行的括号。这可以防止IFS在当前进程中进行修改。

使用您显示的样本,请尝试按照awk程序进行操作。用GNUawk编写和测试,应该适用于任何版本。

awk -v s1="'" -v lines="$(wc -l < Input_file)" '
BEGIN{ OFS="," }
FNR==(lines-1) {
print val
exit
}
FNR>2{
sub(/^[[:space:]]+/,"")
val=(val?val OFS:"") (s1 $0 s1)
}
' Input_file

说明为上面的代码添加详细说明,仅用于说明目的。

awk -v s1="'" -v lines="$(wc -l < Input_file)" '  ##Starting awk program, setting s1 variable to ' and creating lines which has total number of lines in it, using wc -l command on Input_file file.
BEGIN{ OFS="," }                                ##Setting OFS to comma in BEGIN section of this program.
FNR==(lines-1) {                                ##Checking condition if its 2nd last line of Input_file.
print val                                     ##Then printing val here.
exit                                          ##exiting from program from here.
}
FNR>2{                                          ##Checking condition if FNR is greater than 2 then do following.
sub(/^[[:space:]]+/,"")                       ##Substituting initial spaces with NULL here.
val=(val?val OFS:"") (s1 $0 s1)               ##Creating val which has ' current line ' in it and keep adding it in val.
}
' Input_file                                    ##Mentioning Input_file name here.

如果您知道输入足够小,可以放入内存:

$ awk '
NR>4 { gsub(/^ *| *$/,"47",p2); out=out sep p2; sep="," }
{ p2=p1; p1=$0 }
END { print out }
' input.txt
'Abce','Bca','Efr'

否则:

$ awk '
NR>4 { gsub(/^ *| *$/,"47",p2); printf "%s%s", sep, p2; sep="," }
{ p2=p1; p1=$0 }
END { print "" }
' input.txt
'Abce','Bca','Efr'

任何一个脚本都可以在每个Unix盒子上的任何shell中使用任何awk。

这可能对你有用(GNU sed):

sed -E '1,2d;$!H;$!d;x;s/^s*(.*)s*$/'''1'''/mg;s/n[^n]*$//;y/n/,/' file

删除前两行。

将每一行附加到保留空间,最后一行除外(这意味着倒数第二行仍然存在 - 见后面)。

删除除最后一行之外的所有行。

交换到保留空间。

删除每行单词两侧的所有空格,并用单引号将这些单词括起来。

删除最后一行及其换行符。

将所有换行符替换为逗号。

第一个sed -i用空文件覆盖input.txt。您无法将输出写回正在读取的文件,并且sed -i无论如何都不会生成任何输出。

最小的解决方法是取出-i并将命令串到管道中;但是,当然,sed允许您将命令组合到单个脚本中。

len=$(wc -l <input.txt)
sed -e '1,2d' -e "$((len - 3))"',$d' 
-e ':a' 
-e 's/^  (.*) $/'"'\1'/" 
-e N -e '$!ba' -e 's/n/, /g' input.txt >output.txt

(未经测试;如果您的sed不允许多个-e选项,则需要重构以在命令之间使用带有分号或换行符的单个字符串。

这很难编写和调试,而且很脆弱,因为您必须将 shell 的引用功能与sed和这个特定脚本的要求结合起来,而且更固有的是sed它是一种简洁而晦涩的语言。

一个更易读和可维护的解决方案是切换到 Awk,它允许您用更人性化的术语表达逻辑,并且不必从 shell 中获取对算术和字符串格式等简单任务的支持。

awk 'FNR > 2 { sub(/^  /, ""); sub(/ $/, "");
a[++i] = sprintf("47%s47,", $0); }
END { for(j=1; j < i-1; ++j) printf "%s", a[j] }' input.txt >output.txt

这从字面上用逗号替换了所有换行符;也许您实际上想打印换行符而不是最后一行的逗号?

awk 'FNR > 2 { sub(/^  /, ""); sub(/ $/, "");
a[++i] = sprintf("%s47%s47", sep, $0); sep="," }
END { for(j=1; j < i-1; ++j) printf "%s", a[j]; printf "n" }' input.txt >output.txt

如果输入文件非常大,您可能希望重构它,以免将所有行都保留在内存中。 数组a收集格式化的输出,我们打印除END块中的最后两个元素之外的所有元素。

sed -E '
/^-+$/,/^-+$/!d
//d
s/^[[:space:]]*|[[:space:]]*$/'''/g
' input.txt |
paste -sd ,
  • 这使用了一个不适用于所有 sed 实现的技巧,以打印两个模式(在本例中为破折号)之间的行,不包括这些模式。
  • 从好的方面来说,如果----模式位于不同的行号处,它仍然有效。不利的一面是它会中断,如果该模式(仅包含破折号的线)出现奇数次(即不成对,包裹您想要的线)。
  • 然后用单引号开始和结束子行(包括空格)。
  • 最后,管道到paste用逗号替换新行,不包括尾随逗号。

使用sed

$ sed "1,2d; /-/,$ d; s/s+//;s/.*/'&'/" input_file | sed -z 's/n/,/g;s/,$/n/'
'Abce','Bca','Efr'

我将发布一个相当轻巧的sed解决方案。

sed '$d' input.txt | sed "$d; 1,2d; s/^s*|s*$/'/g" | paste -sd ',' > output.txt
  • $d删除带有第一个 sed 的最后一行
  • $d删除最后一行。$用反斜杠转义,因为我们在双引号内。
  • 1,2d删除前两行。
  • s/^s*|s*$/'/g将所有前导和尾随空格替换为单引号。
  • 使用paste连接到单个逗号分隔的字符串。

如果我们知道相关行总是以两个空格开头,那么甚至可以进一步简化。

sed -n "s/s*$/'/; s/^  /'/p" input.txt | paste -sd ',' > output.txt
  • -n禁止打印行,除非被告知
  • s/s*$/'/用单引号替换尾随空格
  • s/^ /'/p替换两个前导空格和匹配的打印行
  • paste连接
<小时 />

然后是一个awk解决方案:

awk -v i=1 -v q=' 'FNR>2 {
gsub(/^[[:space:]]*|[[:space:]]*$/, q)
a[i++]=$0
} END {
for(i=1; i<=length(a)-3; i++)
printf "%s,", a[i]
print a[i++]
}' input.txt > output.txt
  • -v i=1创建一个从 1 开始的 awk 变量
  • -v q='为单引号字符创建一个 awk 变量
  • FNR>2 { ...告诉它只处理生产线 3+
  • gsub(/^[[:space:]]*|[[:space:]]*$/, q)用单引号替换前导和尾随空格
  • a[i++]=$0将行添加到数组
  • END { ...到达文件末尾后处理其余部分
  • for(i=1; i<=length(a)-3; i++)取数组的长度,但减去三 - 代表最后三行
  • printf "%s,", a[i]打印除最后三个条目以外的所有条目,逗号分隔
  • print a[i++]打印下一个条目并完成脚本(跳过最后两个条目)

不是单行,但有效

sed "s/^ */'/;s/$/',/;1,2d;N;$!P;$!D;$d"  | sed ' H;1h;$!d;x;s/n//g;s/,$//'

解释:

s/^ */'/;s/$/',/---> 添加单引号和逗号

N;$!P;$!D;$d---> 删除最后两行

H;1h;$!d;x;s/n//g;s/,$//'---> 加载整个文件并合并所有行并删除最后一个逗号

最新更新