[英]bash insert multiple lines into a text file including variables from an array
[英]Put lines of a text file in an array in bash
我正在从一位同事那里接手一个 bash 脚本,该脚本读取一个文件,处理它并基于当前while
循环中的行打印另一个文件。
我现在需要为其添加一些功能。 我现在遇到的问题是读取一个文件并将每一行放入一个数组中,除了该行的第二列可以为空,例如:
对于以\\t
作为分隔符的文本文件:
A\tB\tC
A\t\tC
对于相同但以,
作为分隔符的 CSV 文件:
A,B,C
A,,C
然后应该给
["A","B","C"] or ["A", "", "C"]
我接手的代码如下:
while IFS=$'\t\r' read -r -a col; do
# Process the array, put that into a file
lp -d $printer $file_to_print
done < $input_file
如果 B 被填充,这会起作用,但 B 现在有时需要为空,因此当输入文件将其保持为空时,创建的数组以及要打印的输出文件只会跳过这个空单元格(然后数组为["A","C"]
)。
我尝试在 awk 上编写整个块,但这带来了它自己的一系列问题,使得调用 lp 命令进行打印变得困难。
所以我的问题是,如何将行中的空单元格保留到我的 bash 数组中,以便稍后调用它并使用它?
非常感谢你。 我知道这可能会很困惑,所以请询问,我会指定。
编辑:请求后,这是我尝试过的 awk 代码。 这里的问题是它只打印最后一个打印请求,而我知道它循环遍历整个文件,并且 lp 命令仍在循环中。
awk 'BEGIN {
inputfile="'"${optfile}"'"
outputfile="'"${file_loc}"'"
printer="'"${printer}"'"
while (getline < inputfile){
print "'"${prefix}"'" > outputfile
split($0,ft,"'"${IFSseps}"'");
if (length(ft[2]) == 0){
print "CODEPAGE 1252\nTEXT 465,191,\"ROMAN.TTF\",180,7,7,\""ft[1]"\"" >> outputfile
size_changer = 0
} else {
print "CODEPAGE 1252\nTEXT 465,191,\"ROMAN.TTF\",180,7,7,\""ft[1]"_"ft[2]"\"" >> outputfile
size_changer = 1
}
if ( split($0,ft,"'"${IFSseps}"'") > 6)
maxcounter = 6;
else
maxcounter = split($0,ft,"'"${IFSseps}"'");
for (i = 3; i <= maxcounter; i++){
x=191-(i-2)*33
print "CODEPAGE 1252\nTEXT 465,"x",\"ROMAN.TTF\",180,7,7,\""ft[i]"\"" >> outputfile
}
print "PRINT ""'"${copies}"'"",1" >> outputfile
close(outputfile)
"'"`lp -d ${printer} ${file_loc}`"'"
}
close("'"${file_loc}"'");
}'
EDIT2:继续尝试找到解决方案,我尝试了以下代码但没有成功。 这很奇怪,因为只执行 printf 而不将其放入数组可以保持格式不变。
$ cat testinput | tr '\t' '>'
A>B>C
A>>C
# Should normally be empty on the second ouput line
$ while read line; do IFS=$'\t' read -ra col < <(printf "$line"); echo ${col[1]}; done < testinput
B
C
对于选项卡,它很复杂。
从手册中的3.5.7 分词:
一系列 IFS 空白字符也被视为分隔符。
由于制表符是“IFS 空白字符”,制表符序列被视为单个分隔符
IFS=$'\t' read -ra ary <<<$'A\t\tC'
declare -p ary
declare -a ary=([0]="A" [1]="C")
您可以做的是将制表符转换为非空白字符,假设它不与字段中的实际数据冲突:
line=$'A\t\tC'
IFS=, read -ra ary <<<"${line//$'\t'/,}"
declare -p ary
declare -a ary=([0]="A" [1]="" [2]="C")
为了避免数据中逗号冲突的风险,我们可以使用一个不常见的ASCII字符:FS,八进制034
line=$'A\t\tC'
printf -v FS '\034'
IFS="$FS" read -ra ary <<<"${line//$'\t'/"$FS"}"
# or, without the placeholder variable
IFS=$'\034' read -ra ary <<<"${line//$'\t'/$'\034'}"
declare -p ary
declare -a ary=([0]="A" [1]="" [2]="C")
它可能只是您的# Process the array, put that into a file
部分。
IFS=, read -ra ray <<< "A,,C"
for e in "${ray[@]}"; do o="$o\"$e\","; done
echo "[${o%,}]"
["A","","C"]
请参阅@Glenn 关于选项卡的出色回答。
我的简单数据文件:
$: cat x # tab delimited, empty field 2 of line 2
a b c
d f
我的测试:
while IFS=$'\001' read -r a b c; do
echo "a:[$a] b:[$b] c:[$c]"
done < <(tr "\t" "\001"<x)
a:[a] b:[b] c:[c]
a:[d] b:[] c:[f]
请注意,我使用了 ^A(一个 001 字节),但您可以使用像逗号或管道 ( |
) 字符这样简单的东西。 根据您的数据进行选择。
一个使用参数扩展的bash
示例,我们将分隔符转换为\\n
并让mapfile
在每一行中作为新的数组条目读取...
对于制表符分隔的数据:
for line in $'A\tB\tC' $'A\t\tC'
do
mapfile -t array <<< "${line//$'\t'/$'\n'}"
echo "############# ${line}"
typeset -p array
done
############# A B C
declare -a array=([0]="A" [1]="B" [2]="C")
############# A C
declare -a array=([0]="A" [1]="" [2]="C")
注意: $'...'
构造确保\\t
被视为单个<tab>
字符,而不是两个文字字符\\
+ t
。
对于逗号分隔的数据:
for line in 'A,B,C' 'A,,C'
do
mapfile -t array <<< "${line//,/$'\n'}"
echo "############# ${line}"
typeset -p array
done
############# A,B,C
declare -a array=([0]="A" [1]="B" [2]="C")
############# A,,C
declare -a array=([0]="A" [1]="" [2]="C")
注意:这显然 (?) 假定所需的数据不包含逗号 ( ,
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.