这段代码的输出是两个txt文件。我可以为他们两个做一个 for 循环吗?即一个 for 循环给我两个或多个输出?在 ID1 和 ID2 中我有文件名。我想打印 ID1 和 ID2 中每个条目的第一行并将其保存为 output1 和 output2 但我不想使用两个 for 循环。我正在寻找的是一个 for 循环来完成这项工作。
#!/bin/bash
in=/a/b/c
li=/a/b/c/d/
g1=/a/s/t1/1.txt
g2=/a/s/t2/2.txt
for i in $(cat $li/ID1.txt); do
sed '1q;d' ${in}/${i}/${g1};
done > output1.txt
for i in $(cat $li/ID2.txt); do
sed '1q;d' ${in}/${i}/${g2};
done > output2.txt
答案1
好吧,我想我现在明白变量中的路径名的作用了。
for n in 1 2; do n=$n.txt
for f in $(cat "$li/ID$n")
do IFS= read -r l <"$in/$f/a/s/t${n%.*}/$n"
printf %s\\n "$l"
done > "output$n"; done
我思考这就能实现你所追求的目标。如果是这样,它会使用 shell 内置函数来完成所有操作 - 也就是说,除了cat
.
说到- 当像这里那样cat
分割时,重要的是要明确 的值并避免在扩展中解释文件名全局。因为我不知道该文件的内容,所以我无法提供更多建议。$IFS
for ... in $(cmd sub)
$IFS
set -f
另一种方法可能涉及空字符串分隔符。这在很大程度上取决于$IFS
分裂——它取决于扩张不是包括任何空字符串,因为它使用空字符串作为标记。如果您不更改$IFS
并将其设置为默认值,则$(cat file)
扩展将不包含任何空字符串。它可能是这样的:
io=/a/s/t1/1.txt
for f in $(cat "$li/ID1.txt") '' $(cat "$li/ID2.txt")
do [ -z "$f" ] && io=/a/s/t2/2.txt && continue
IFS= read -r l <"$in/$f/$io"
printf %s\\n "$l" >> "output${io##*/}"
done
或者你甚至可能会做...
n=0
for f in '' $(cat "$li/ID1.txt") '' $(cat "$li/ID2.txt")
do [ -z "$f" ] && exec >"output$((n+=1)).txt" && continue
IFS= read -r l <"$in/$f/a/s/t$n/$n.txt"
printf %s\\n "$l"
done
答案2
在这种特殊情况下,您根本不需要循环:
#!/usr/bin/env bash
in=/a/b/c
li=/a/b/c/d/
g1=/a/s/t1/1.txt
g2=/a/s/t2/2.txt
files1=$(sed "s#^#${in}/#;s#\$#/${g1}#" $li/ID1.txt | tr '\n' ' ')
files2=$(sed "s#^#${in}/#;s#\$#/${g2}#" $li/ID2.txt | tr '\n' ' ')
head -qn 1 $files1 > output1
head -qn 1 $files2 > output2
用于files1=...
添加sed
到$in
每行的开头和$g1
结尾。这应该会产生目标文件名列表。然后您可以将所有的传递给sed
打印第一行的。
重要的:这假设您的文件名是正常的(不包含空格、换行符或其他奇怪的字符)。如果情况并非如此,请告诉我,我会尽力提供更可靠的答案。请注意,您最初的for
循环方法对于带有空格的文件名也会失败。
一般来说,无论您使用哪种语言,如果您发现自己编写重复的代码,您应该考虑使用函数:
#!/usr/bin/env bash
in=/a/b/c
li=/a/b/c/d/
g1=/a/s/t1/1.txt
g2=/a/s/t2/2.txt
firstline(){
_in="$1"
_g="$2"
file="$3"
while read i
do
sed '1q;d' ${in}/${i}/${g}
done < "$file"
}
firstline "$li/ID1.txt" "$in" "$g1" > output1.txt
firstline "$li/ID2.txt" "$in" "$g2" > output2.txt