我有2个脚本,#1和#2。每个工作都可以自己做。我想逐行读取15行文件并进行处理。脚本#2选择行。行0表示为firstline = 0,lastline = 1。第14行是firstline = 14,lastline = 15。我看到echo的结果很好。我想用脚本#1做同样的事情。无法正确嵌套。代码如下。
#!/bin/bash
# script 1
filename=slash
firstline=0
lastline=1
i=0
exec <${filename}
while read ; do
i=$(( $i + 1 ))
if [ "$i" -ge "${firstline}" ] ; then
if [ "$i" -gt "${lastline}" ] ; then
break
else
echo "${REPLY}" > slash1
fold -w 21 -s slash1 > news1
sleep 5
fi
fi
done
# script2
firstline=(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14)
lastline=(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
for ((i=0;i<${#firstline[@]};i++))
do
echo ${firstline[$i]} ${lastline[$i]};
done
答案 0 :(得分:1)
你的问题很不清楚,但也许你只是在寻找一些简单的函数调用:
#!/bin/bash
script_1() {
filename=slash
firstline=$1
lastline=$2
i=0
exec <${filename}
while read ; do
i=$(( $i + 1 ))
if [ "$i" -ge "${firstline}" ] ; then
if [ "$i" -gt "${lastline}" ] ; then
break
else
echo "${REPLY}" > slash1
fold -w 21 -s slash1 > news1
sleep 5
fi
fi
done
}
# script2
firstline=(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14)
lastline=(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
for ((i=0;i<${#firstline[@]};i++))
do
script_1 ${firstline[$i]} ${lastline[$i]};
done
请注意,以这种方式读取文件效率非常低,并且毫无疑问有更好的方法来处理这个问题,但我正在尝试最小化代码中的更改。
答案 1 :(得分:1)
更新:根据您之后的评论,使用sed
提取每次迭代中感兴趣的行的以下惯用Bash代码可以更加简单地解决您的问题:
注意:
- 如果输入文件在循环迭代之间没有变化,并且输入文件足够小(就像在手边的情况下那样),那么预先在变量中缓冲文件内容会更有效,因为在下面的原始答案中证明
- 正如tripleee在评论中指出:如果只是按顺序读取输入行 就足够了(而不是通过特定行号提取行,那么单个,简单while read -r line; do ... # fold and output, then sleep ... done < "$filename"
就足够了。
功能
# Determine the input filename.
filename='slash'
# Count its number of lines.
lineCount=$(wc -l < "$filename")
# Loop over the line numbers of the file.
for (( lineNum = 1; lineNum <= lineCount; ++lineNum )); do
# Use `sed` to extract the line with the line number at hand,
# reformat it, and output to the target file.
fold -w 21 -s <(sed -n "$lineNum {p;q;}" "$filename") > 'news1'
sleep 5
done
我想要您尝试实现的内容的简化版本:
#!/bin/bash
# Split fields by newlines on input,
# and separate array items by newlines on output.
IFS=$'\n'
# Read all input lines up front, into array ${lines[@]}
# In terms of your code, you'd use
# read -d '' -ra lines < "$filename"
read -d '' -ra lines <<<$'line 1\nline 2\nline 3\nline 4\nline 5\nline 6\nline 7\nline 8\nline 9\nline 10\nline 11\nline 12\nline 13\nline 14\nline 15'
# Define the arrays specifying the line ranges to select.
firstline=(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14)
lastline=(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
# Loop over the ranges and select a range of lines in each iteration.
for ((i=0; i<${#firstline[@]}; i++)); do
extractedLines="${lines[*]: ${firstline[i]}: 1 + ${lastline[i]} - ${firstline[i]}}"
# Process the extracted lines.
# In terms of your code, the `> slash1` and `fold ...` commands would go here.
echo "$extractedLines"
echo '------'
done
注意:
填充read -ra
的数组变量的名称为lines
; ${lines[@]}
是用于将所有数组元素作为单独的单词返回的Bash语法(${lines[*]}
也引用所有元素,但语义略有不同),并且在语句中使用此语法说明lines
确实是一个数组变量(请注意,如果您只使用$lines
来引用该变量,则您只能隐式获取该项目index 0
,与:${lines[0]}
相同。
<<<$'line 1\n...'
使用here-string(<<<
)阅读ad-hoc 示例文档(表示为ANSI C-quoted string( $'...'
))为了使我的示例代码自包含。
$filename
读取:read -d '' -ra lines <"$filename"
extractedLines="${lines[*]: ${firstline[i]}: 1 + ${lastline[i]} - ${firstline[i]}}"
提取感兴趣的线条; ${firstline[i]}
引用数组i
中的当前元素(索引${firstline[@]}
);自Bash的阵列切片语法中的最后一个标记
(${lines[*]: <startIndex>: <elementCount>}
)是要返回的元素的 count ,我们必须执行计算来确定计数,这是1 + ${lastline[i]} - ${firstline[i]}
所做的。< / p>
"${lines[*]...}"
而不是"${lines[@]...}"
,提取的数组元素由$IFS
中的第一个字符连接,在我们的示例中为新行($'\n'
)(当提取单个行时,这并不重要)。