Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 在文件中搜索双引号(";),并将整行复制到不同的文件中_Bash_Shell_Awk_Sed - Fatal编程技术网

Bash 在文件中搜索双引号(";),并将整行复制到不同的文件中

Bash 在文件中搜索双引号(";),并将整行复制到不同的文件中,bash,shell,awk,sed,Bash,Shell,Awk,Sed,我需要通读所有文件并查找(“),然后将整行复制到另一个文件中。这里的挑战是当行中有新字符时识别整行 文件格式如下-值用分隔符*.分隔,并以|#|结尾 在所附的(图像)中,以绿色突出显示的应该转到新文件,逻辑将检查“,如果它发现读取行从(在|##| |到下一个|#|)开始) 假设您的意思是|##|之间的部分应视为换行符,下一个问题是您的文件是否包含任何真正的换行符?如果不是这样,grep可能不会非常有效,因为它是逐行工作的。如果有任何真正的新词被认为是文本的一部分,那么毫无疑问,格雷普会不高兴的

我需要通读所有文件并查找(“),然后将整行复制到另一个文件中。这里的挑战是当行中有新字符时识别整行

文件格式如下-值用分隔符
*.
分隔,并以
|#|
结尾

在所附的(图像)中,以绿色突出显示的应该转到新文件,逻辑将检查
,如果它发现读取行从(在|##| |到下一个|#|)开始)


假设您的意思是
|##|
之间的部分应视为换行符,下一个问题是您的文件是否包含任何真正的换行符?如果不是这样,
grep
可能不会非常有效,因为它是逐行工作的。如果有任何真正的新词被认为是文本的一部分,那么毫无疑问,格雷普会不高兴的

如果您真的想在1中完成,请使用grep:

(3)本周四周四周四周四周四周四周四周四周四周五周五周五周五周五-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |$)'

这是查找以|#|#|开头(或文件开头)后跟一些字符、引号和更多字符,然后以|##|(或文件结尾)结尾的任何序列。使用-z grep将忽略文件中的任何换行。 复杂的“任意字符”
([^ |][124;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/code>表达式是因为grep是贪婪的。它基本上寻找的是不属于贪婪的重复序列。也许关闭贪婪是好的,但这将取决于grep版本中regexp引擎的强大程度

但使用sed分解记录并注入“NULL”换行符要容易得多,而且可能更快:

sed's/\\\\\\\\\\\\\\\\\x00/g''grep-z''


这只是将您的行尾模式|##|替换为空字符,然后让grep查找引号,同时将空字符视为行尾。

此答案提供了两种解决方案—Gnu Awk解决方案和POSIX版本

POSIX awk

awk '{r=r ? r "\n" $0 : $0}
     /\|##\|$/ { if (r ~ /"/) print r; r=""}' inputfile > outputfile
GNU awk 1

awk 'BEGIN{RS="\\|##\\|\n?";ORS="|##|\n"}/"/' inputfile > outputfile
GNU awk 2

awk 'BEGIN{RS="\\|##\\|\n?"}/"/{printf $0 RT}' inputfile > outputfile
根据问题中提供的样本数据,所有提供的解决方案都给出了以下输出:

10358|*|BI-MED-CDMA-MCS-90-118-EXAM|*|Exam for 001-MCS-90-118:
Planning, Conducting and Reporting Post Marketing Surveillance "Studies and Safety Reporting from Non Trial Activities |*|GLOBAL_MEDICAL|*||*|Y|*|N|*||*|CFC6E822849A0A7AE040800AA5644B19|*|finke|*|2012.04.30 04:23:27|##|
注意:如果文件来自Windows计算机,则可能存在回车问题。请先在文件上运行
dos2unix
,然后再将其与这些工具一起使用


这是如何工作的?(POSIX)

使用POSIX版本的

awk '{r=r ? r "\n" $0 : $0}
      /\|##\|$/ { if (r ~ /"/) print r; r=""}' inputfile > outputfile
这个想法是通过将每一行追加到
r
来建立一个记录
r
。如果当前行以
“|#| |”
结尾,则检查记录
r
是否包含
。如果是这种情况,则打印记录
r
,并将记录
r
重置为空字符串。如果它不包含

这是如何工作的?(GNU)

使用GNU,您可以直接使用记录分隔符
RS

awk 'BEGIN{RS="\\|##\\|\n?";ORS="|##|\n"}/"/' inputfile > outputfile
这里的想法是,文件包含各种记录。OP清楚地说明,记录的信息被拆分为由
*.
分隔的字段,但更重要的是,记录本身被
.\35;.
分隔。因此,在OP的示例中,第一条记录是第1行,而第二条记录是分散的第2行和第3行

在中,您可以通过变量
RS
定义记录分隔符。在其默认状态下,
RS
是字符
\n
,它使每一行都成为一个单独的记录,可以被
$0
引用。在POSIX中,记录分隔符只能是一个单独的字符,用于分隔记录,而在Gnu awk中,这可以是一个正则表达式(见下面的附录)

由于OP的记录分隔符是字符串“|##|”后跟或不后跟字符
\n
,因此我们需要定义
RS=\\\\\\\\\\\\\\\\n?
。为什么这么复杂

  • 符号是正则表达式中的OR运算(交替运算符),因此我们需要对其进行转义。但是,由于用作正则表达式的字符串文本被解析两次,因此我们也需要对其进行转义两次。因此
    →
    \\\\
    (请参阅)

  • 之所以使用
    \n?
    是因为实际的记录分隔符似乎是字符串“|##|\n”,但可能有些记录没有换行符,尤其是最后一条记录

打印记录时,使用
print
语句,它会在每行后面自动附加输出记录分隔符
ORS
。默认情况下,这也是一个字符
\n
。由于记录分隔符
RS
不是记录
$0
的一部分,因此需要将值
ORS
更新为
>ORS=“|#| |\n”
。这次不是正则表达式,所以根本不需要转义

语句
/“/
/“/{print$0}
的简写,这意味着如果当前记录
$0
包含
,则打印当前记录
$0
,后跟输出记录分隔符
OR

注意:由于我们实际上已经使用了Gnu awk,我们实际上可以将整个过程进一步简化为:

awk 'BEGIN{RS="\\|##\\|\n?"}/"/{printf $0 RT}' inputfile > outputfile
它使用匹配的记录分隔符
RT
,该分隔符对应于
RS
找到的文本。通过将
print
语句替换为
printf
语句,我们不再需要
or
,只需手动将
RT
添加到记录
$0


RS
输入记录分隔符。它的默认值是一个包含单个换行符的字符串,这意味着输入记录由一行文本组成。它也可以是
awk 'BEGIN{RS="\\|##\\|\n?"}/"/{printf $0 RT}' inputfile > outputfile