我正在尝试制作一个小 bash 脚本,该脚本对使用该命令找到的文件中的每个文件调用一个命令find
。
我希望能够跟踪脚本停止的位置(它往往会崩溃),以便我可以从那里返回。我设法读取我的文件,获取行,...但目前我陷入了 for 循环。我想做一个 C 风格的 for 循环,从我停止的最后一行开始,递增一,只要我小于行数就这样做。我懂了 :
#!/bin/bash
LINES=$(wc -l < file.txt)
LASTLINE=$(grep -P '### Stop marker ###' file.txt | wc -l)
STARTFROM=$(($LINES - $LASTLINE))
for ((i = STARTFROM; i < LINES; i++));
do
echo "we are processing file number $i"
file=sed -n $i'p' file.txt
ocrmypdf [some stuff] -input $file
done
file.txt
这是我的内部外观的摘录
./input_folder/hard_blurry.pdf
./input_folder/l_ordre_malte.pdf
### Stop marker ###
./input_folder/single_page.pdf
./input_folder/very_hard.pdf
当我运行这个时,我什么也没得到。 Bash 根本不进入循环。我尝试直接设置整数,它起作用了,这告诉我变量被读取为字符串。
我尝试了所有这些方法来编写我的 var :
for ((i = STARTFROM; i < LINES; i++));
for ((i = $((STARTFROM)); i < $((LINES)); i++));
for ((i = $(echo STARTFROM); i < $(echo LINES); i++));
没有任何效果。我很惊讶也没有抛出任何错误。我的操作系统是ubuntu 20.0.4
它的内容是我想要使用的文件的路径。
有任何想法吗 ?谢谢
答案1
LASTLINE=$(grep -P '### Stop marker ###' file.txt | wc -l)
这会告诉你多少线条与该模式匹配,但与它们所在的位置不匹配。如果文件中有一个标记,则返回1
.您需要使用类似grep -n
( --line-number
) 的内容来获取行号。
file=sed -n $i'p' file.txt
这可能应该是file=$(sed ...)
,即用命令替换来捕获 的输出sed
。但是,如果您在循环中执行此操作,则每次循环迭代都会读取整个文件,这是一种愚蠢的浪费,并且如果文件很长,则需要很长时间。
这就是问题所在 为什么使用 shell 循环处理文本被认为是不好的做法?之前链接在这里提到的。请注意,不好的做法是加工,修改文本。使用 shell 根据文件中的某些数据运行命令就可以了; shell 的存在是为了运行命令。
因此,只需循环一次文件并检测 shell 中的停止标记:
#!/bin/bash
i=0
while IFS= read -r line; do
if [[ $line == '### Stop marker ###' ]]; then
break;
fi
i=$((i + 1))
echo "line $i, do some stuff with '$line'"
done < file.txt
(是 Ksh-ism。它可以在 POSIX shell 中[[ .. ]]
替换为。)case
或者,让一些外部文本处理工具处理停止标记并让 shell 运行命令:
#!/bin/sh
i=0
< file.txt sed -n -e '/### Stop marker ###/q' -e p |
while IFS= read -r line; do
i=$((i + 1))
echo "line $i, do some stuff with '$line'"
done
如果如果您确实想要执行for (i = 0; i < end; i++)
样式循环,则可以首先将整个文件读入数组,但除非您需要随机访问行,否则完全没有必要。流式传输文件要自然得多。
答案2
你可以像这样的 seq 来获取 var 的范围:
#!/bin/bash
LINES=1
LASTLINE=10
for i in $(seq $LINES $LASTLINE )
do
echo $i
done
输出:
1
2
3
4
5
6
7
8
9
10