fue*_*zig 5 bash shell batch-processing
那个设定:
我有几百文件,名字类似input0.dat,input1.dat..., input150.dat,我需要使用一些命令来处理cmd(这基本上合并所有文件的内容)。在cmd需要作为第一选择输出文件名,然后所有的输入文件名列表:
./cmd output.dat input1.dat input2.dat [...] input150.dat
Run Code Online (Sandbox Code Playgroud)
问题:
问题是由于内存问题,脚本只能处理10个左右的文件(不要怪我)。因此,不要bash像这样使用通配符扩展名
./cmd output.dat *dat
Run Code Online (Sandbox Code Playgroud)
我需要做类似的事情
./cmd temp_output0.dat file0.dat file1.dat [...] file9.dat
[...]
./cmd temp_outputN.dat fileN0.dat fileN1.dat [...] fileN9.dat
Run Code Online (Sandbox Code Playgroud)
之后,我可以合并临时输出。
./cmd output.dat output0.dat [...] outputN.dat
Run Code Online (Sandbox Code Playgroud)
如何有效地编写脚本bash?
我尝试过但没有成功,例如
for filename in `echo *dat | xargs -n 3`; do [...]; done
Run Code Online (Sandbox Code Playgroud)
问题在于这会再次处理所有文件,因为xargsget 的输出行是连接在一起的。
编辑:请注意,我在调用cmd!时需要指定输出文件名作为第一个命令行参数。
尝试以下操作,它应该对您有用:
echo *dat | xargs -n3 ./cmd output.dat
Run Code Online (Sandbox Code Playgroud)
编辑:回应您的评论:
for i in {0..9}; do
echo file${i}*.dat | xargs -n3 ./cmd output${i}.dat
done
Run Code Online (Sandbox Code Playgroud)
这将一次发送不超过三个文件到./cmd,同时检查从file00.dat到的所有文件file99.dat,并有 10 个不同的输出文件output1.dat到output9.dat。
编辑没有管道或进程替换 - 需要 bash。这能够处理名称中带有空格的文件。使用 bash 数组并提取切片:
i=0
infiles=(*dat)
opfiles=()
while ((${#infiles[@]})); do
threefiles=("${infiles[@]:0:3}")
echo ./cmd tmp_output$i.dat "${threefiles[@]}"
opfiles+=("tmp_output$i.dat")
((i++))
infiles=("${infiles[@]:3}")
done
echo ./cmd output.dat "${opfiles[@]}"
rm "${opfiles[@]}"
Run Code Online (Sandbox Code Playgroud)
使用 fifo - 这无法处理文件名中的空格:
i=0
opfiles=
mkfifo /tmp/foo
echo *dat | xargs -n 3 >/tmp/foo&
while read threefiles; do
./cmd tmp_output$i.dat $threefiles
opfiles="$opfiles tmp_output$i.dat"
((i++))
done </tmp/foo
rm -f /tmp/foo
wait
./cmd output.dat $opfiles
rm $opfiles
Run Code Online (Sandbox Code Playgroud)
您需要使用 fifo 来保存i变量值以及最终的文件串联集。
如果需要,您可以将 的内部调用置于后台,在最后一次调用 cmd 之前./cmd放置一个:wait
i=0
opfiles=
mkfifo /tmp/foo
echo *dat | xargs -n 3 >/tmp/foo&
while read threefiles; do
./cmd tmp_output$i.dat $threefiles&
opfiles="$opfiles tmp_output$i.dat"
((i++))
done </tmp/foo
rm -f /tmp/foo
wait
./cmd output.dat $opfiles
rm $opfiles
Run Code Online (Sandbox Code Playgroud)
更新 如果您想完全避免使用 fifo,您可以使用进程替换来模拟它,因此将第一个重写为:
i=0
opfiles=()
while read threefiles; do
./cmd tmp_output$i.dat $threefiles
opfiles+=("tmp_output$i.dat")
((i++))
done < <(echo *dat | xargs -n 3)
./cmd output.dat "${opfiles[@]}"
rm "${opfiles[@]}"
Run Code Online (Sandbox Code Playgroud)
再次避免管道进入 while,而是从重定向中读取以opfiles在 while 循环之后保留变量。