我有一个超级复杂的 bash 脚本,它从一个大型输出文件中提取结果(在 LINUX 机器上生成,以防万一这相关)。作为此过程的一部分,我使用 grep、head、tail 等的组合从这个较大的文件中提取子部分;然后将此文本子部分保存到临时文件中,然后进一步处理。我在这里提供了一个更简单的例子,这样我就可以提出我的问题,即:
我怎样才能避免保存到这个临时文件?
我想要做的是,不是将这部分文本保存到临时文件中,而是将数据子部分(包括回车符)保存到 bash 变量中,然后可以进一步处理。
问题是我编写的 bash 脚本没有“看到”回车符。在下面的示例中,我有一个文件“exampledata.data”,其中包含以下文本:
START_BLOCK #1
line a b c
line b
END_BLOCK #1
START_BLOCK #2
Line 1 2
Line 2 7
Line 3
Line 4
END_BLOCK #2
START_BLOCK #3
Line x s d e f
END_BLOCK #3
我的原始脚本(保存到临时文件)按预期工作,awk 命令正确显示每个“块”内所有行的第二个标记:
#!/bin/bash
file="examplefile.data" # File to process
totblock=`grep "START_BLOCK" $file | wc -l` # Determine number of blocks of data in file
# Current implementation - which works
for ((l=1; $l<=${totblock}; l++)); do # Loop through each block of data
echo "BLOCK "$l
# display file contents -> extract subsection of data for current block -> Remove top and bottom -> Save to temporary file
cat $file | \
sed -n '/START_BLOCK #'${l}'/,/END_BLOCK #'${l}'/p' | \
grep -Ev "START|END" > TEMPFILE
# Perform some rudimentary processing on this temporary file to check the overall process is working
awk '{print $2}' TEMPFILE
done
rm TEMPFILE
如果我尝试将本来要保存到 TEMPFILE 的内容保存到 bash 变量 (bashvar),则所有回车符都会丢失,导致一行很长。因此,awk 命令实际上只显示第一行的第二个标记,这不是我想要的:
#!/bin/bash
file="examplefile.data" # File to process
totblock=`grep "START_BLOCK" $file | wc -l` # Determine number of blocks of data in file
# New implementation with the aim to avoid the need to write to a temporary file (TEMPFILE)
for ((l=1; $l<=${totblock}; l++)); do
echo "BLOCK "$l
# As above but rather than piping the output to a file, save it to a bash-variable
bashvar=`cat $file | \
sed -n '/START_BLOCK #'${l}'/,/END_BLOCK #'${l}'/p' | \
grep -Ev "START|END"`
# Perform the same rudimentary test to confirm the overall process is working
echo $bashvar | awk '{print $2}'
done
首先,你真的不想在 bash或任何其他 shell 中执行此类操作。请使用真正的编程语言。它会更简单、更快速、更高效。
也就是说,这对您不起作用的原因是因为您没有引用变量,因此 shell 应用split + glob。因此,只需将您的最终
echo
命令更改为以下内容即可:但是,您可以在此处解决各种其他问题并进行改进。 命令
grep
可以为您计入,无需wc
。您应该避免使用 ,而应var=`command`
使用。您应该引用所有变量。使用创建临时文件(如果您想避免使用文件,则无关紧要,但下次请记住)。避免硬编码文件名,而应使用参数。使用确保完全匹配(因此不被视为 的匹配)。您不需要,您可以直接执行。在 之后不需要,您可以在 上换行。这是考虑到所有这些因素的脚本版本:var=$(command)
mktemp
grep -w
NOT_A_START_BLOCK
START_BLOCK
cat "$file" | sed
sed "$file"
\
|
|
请注意,这在任何其他语言中都会更好。既然你正在使用
awk
,为什么不在 awk 中完成整个事情呢?我建议您发布一个新问题,描述您正在进行的实际处理并寻求解决方案。在 bash 中循环遍历文本文件的各个部分确实不是一个好主意。