Adn*_*Ali 6 command-line text-processing
我有包含 14000 多行的文本文件。它包含一些我用于语音识别数据训练的数据。
我通过 Java 编码创建了该文件,并且由于一些语义错误,其中几行是空的。每次我运行训练时,它都会在大约 30 分钟后出现错误,抱怨有一个空行。
是否有任何代码/脚本/命令可以为我提供带有空行的行号列表,以便我可以填充这些空行并节省我的时间?
工作应该是这样的:
我会输入一个file.txt它会给我
line number 1121,1212,1450,13000 and so on ... 是空的 file.txt
wal*_*tor 15
您可以找到空行及其行号,
grep -E --line-number --with-filename '^$' file.txt
Run Code Online (Sandbox Code Playgroud)
一个例子:
w3@aardvark:~(0)$ grep -E --line-number --with-filename '^$' file.txt
file.txt:1:
file.txt:3:
file.txt:4:
w3@aardvark:~(0)$ cat -n file.txt
1
2 Not empty
3
4
5 Not empty
w3@aardvark:~(0)$
Run Code Online (Sandbox Code Playgroud)
如果您的“空”行包含空格或制表符,请使用:
grep -E --line-number --with-filename '^\s*$' file.txt
Run Code Online (Sandbox Code Playgroud)
sed将使用=命令报告行号,因此您可以使用此表达式报告空行的行号(在^(行首)和$(行尾)之间没有任何内容的行):
sed -n '/^$/=' file
Run Code Online (Sandbox Code Playgroud)
我们使用-n选项来抑制打印流(当我们使用 时=,行号与行本身分开打印,因此这里没有p命令),因此唯一的输出是匹配行的行号。
$ sed -n '/^$/=' foo
1
3
5
7
Run Code Online (Sandbox Code Playgroud)
(如果第 1、3、5 和 7 行在 中为空foo)
下面是一个示例,展示了如何获得所需的用户交互。您可以使用任何解决方案来代替sed这些结构中的表达式...
$ cat foo
2
4
6
8
Run Code Online (Sandbox Code Playgroud)
所以:
$ read -p "Enter file name: "; echo -e "The following lines are empty in "$REPLY":\n$(sed -n '/^$/=' "$REPLY" | tr '\n' ' ')"
Enter file name: foo
The following lines are empty in foo:
1 3 5 7
Run Code Online (Sandbox Code Playgroud)
(tr '\n' ','用于获取逗号而不是空格)
您可以另存为脚本(我将其命名为我的empline):
#!/bin/bash
read -p "Enter file name: "
echo -e "The following lines are empty in "$REPLY":\n\
$(sed -n '/^$/=' "$REPLY" | tr '\n' ' ')"
Run Code Online (Sandbox Code Playgroud)
使脚本可执行:
chmod u+x empline
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样运行它
$ ./empline
Enter file name: foo
The following lines are empty in foo:
1 3 5 7
Run Code Online (Sandbox Code Playgroud)
你可以跳过read线并更换"$REPLY"与"$1"使用文件名作为参数的位置(所以运行./empline foo)。为了简化使用,您可以创建一个函数并添加到您的末尾~/.bashrc:
function empline() {
echo -e "The following lines are empty in "$1":\n\
$(sed -n '/^$/=' "$1" | tr '\n' ' ')"
}
Run Code Online (Sandbox Code Playgroud)
这将文件名作为参数:
$ empline foo
The following lines are empty in foo:
1 3 5 7
Run Code Online (Sandbox Code Playgroud)
awk多文件输入的方法(见文章末尾)是最健壮的。
awk 'BEGIN { printf "Line numbers of empty lines in " ARGV[1] ": " } !NF { printf sep NR ; sep="," } END { printf "\n" }' file.txt
Run Code Online (Sandbox Code Playgroud)
该BEGIN部分在处理输入文件之前运行。
ARGV[1]是输入文件的名称。这对应于awk的FILENAME变量,在BEGINsection中不起作用。
!NF匹配空白行或仅包含字段分隔符的行。默认字段分隔符是空格和制表符,因此仅包含空格和制表符的行算作空。 NF(不带感叹号)匹配包含数据的行,添加会! 反转匹配。
NR是当前正在评估的输入文件的行号。 NR如果在命令行上指定了其他输入文件,则不会重置为 1。
为了防止逗号出现在第一个匹配的行号之前,请sep在打印第一个匹配之前保持未定义字符串。
该END部分在处理输入文件后运行。在此示例中,它通过打印 Unix 样式的换行符干净地终止输出。
示例输出:
Line numbers of empty lines in file.txt: 8,13,15,20,25,28
Run Code Online (Sandbox Code Playgroud)
即使您最初希望它为空,在没有首先设置它的情况下使用字符串名称也有点草率。您可以sep在该BEGIN部分中将字符串显式设置为空:
awk 'BEGIN { sep="" ; printf "Line numbers of empty lines in " ARGV[1] ": " } !NF { printf sep NR ; sep="," } END { printf "\n" }' file.txt
Run Code Online (Sandbox Code Playgroud)
awk 'FNR==1 && NR>1 { printf "\n" } FNR==1 { sep="" ; printf "Line numbers of empty lines in " FILENAME ": " } !NF { printf sep FNR ; sep="," } END { printf "\n" }' file1.txt file2.txt file3.txt
Run Code Online (Sandbox Code Playgroud)
FNR与 类似NR,不同之处在于FNR行号计数器在每个文件的开头重置为 1。
该部分FNR==1 && NR>1 { printf "\n" }使每个文件的输出打印在单独的行上。它打印换行符当每个的第一行的附加输入文件被处理,但不适合的第一行第一文件。
示例输出:
Line numbers of empty lines in file1.txt: 8,13,15,20,25,28
Line numbers of empty lines in file2.txt: 1,2,4,6,7,9,10
Line numbers of empty lines in file3.txt: 3,8,9,11,13,15
Run Code Online (Sandbox Code Playgroud)
纯猛砸,使用示例文件foo从赞纳的回答:
i=0
while read line; do
((++i))
if [[ $line == '' ]]; then
echo $i
fi
done < foo
Run Code Online (Sandbox Code Playgroud)
输出:
1
3
5
7
Run Code Online (Sandbox Code Playgroud)
或者,您可能更喜欢使用以下命令的Python 解决方案的 Bash 等效项enumerate():
cat -n foo |
while read -r i line; do
if [[ $line == '' ]]; then
echo $i
fi
done
Run Code Online (Sandbox Code Playgroud)