是否有基于分隔符合并2个文件的特定bash命令?
我正在尝试将2个文件合并为1个文件,但具体方式不同。我目前使用嵌套的while循环执行此操作,但想知道是否有更简单的方法或命令。假设我有以下文件 文件1 文件2是否有基于分隔符合并2个文件的特定bash命令?,bash,merge,Bash,Merge,我正在尝试将2个文件合并为1个文件,但具体方式不同。我目前使用嵌套的while循环执行此操作,但想知道是否有更简单的方法或命令。假设我有以下文件 文件1 文件2 B B B B B B B B 为了简化这个问题,我写了A和B,但文件中可以包含其他行。 这两个文件需要合并并保存到一个变量中,因为它将在我的bash程序中进一步使用,该变量必须包含以下内容: 1:A 2:B 2:B 1:A 1:A 1:A 2:B 2:B 2:B 2:B 2:B 2:B # read file as a bl
B
B
B
B
B
B
B
B
为了简化这个问题,我写了A和B,但文件中可以包含其他行。
这两个文件需要合并并保存到一个变量中,因为它将在我的bash程序中进一步使用,该变量必须包含以下内容:
1:A
2:B
2:B
1:A
1:A
1:A
2:B
2:B
2:B
2:B
2:B
2:B
# read file as a blank-line-separated array
readlines() {
local file="$1"
local -n array="$2"
local num="$3"
local line
local i=0
while IFS= read -r line; do
if [[ -z $line ]]; then
((i++))
else
array[i]+="$num:$line"$'\n'
fi
done < "$file"
}
min() {
local x="$1"
local y="$2"
if (( x < y )); then
echo "$x"
else
echo "$y"
fi
}
declare -a a b
readlines "file1" "a" "1"
readlines "file2" "b" "2"
m=$(min "${#a[@]}" "${#b[@]}")
# interleaving part
for (( i=0; i<m; i++ )); do
echo -n "${a[i]}${b[i]}"
done
# remaining part
if (( ${#a[@]} < ${#b[@]} )); then
for (( i=m; i<${#b[@]}; i++ )); do
echo -n "${b[i]}"
done
else
for (( i=m; i<${#a[@]}; i++ )); do
echo -n "${a[i]}"
done
fi
正如您所看到的,如果一个文件有多个组(一个组是多行,没有空行),则文件会根据换行符合并在一起,而不是仅在彼此之后添加。此外,还必须根据行来自哪个文件添加1或2。是否有一个简单的命令(而不是awk)来解决这个问题,而不是嵌套的whiles
更多信息编辑
这两个文件必须用分隔符“空行”合并,这样您可以从file1的第一行开始,直到一个空行,然后添加file2的行,直到一个空行。如果一个文件没有更多的行,则只会添加另一个文件的其他行。这些行还必须有一个指示,指示这些行是来自文件1还是文件2。是否尝试以下操作:
1:A
2:B
2:B
1:A
1:A
1:A
2:B
2:B
2:B
2:B
2:B
2:B
# read file as a blank-line-separated array
readlines() {
local file="$1"
local -n array="$2"
local num="$3"
local line
local i=0
while IFS= read -r line; do
if [[ -z $line ]]; then
((i++))
else
array[i]+="$num:$line"$'\n'
fi
done < "$file"
}
min() {
local x="$1"
local y="$2"
if (( x < y )); then
echo "$x"
else
echo "$y"
fi
}
declare -a a b
readlines "file1" "a" "1"
readlines "file2" "b" "2"
m=$(min "${#a[@]}" "${#b[@]}")
# interleaving part
for (( i=0; i<m; i++ )); do
echo -n "${a[i]}${b[i]}"
done
# remaining part
if (( ${#a[@]} < ${#b[@]} )); then
for (( i=m; i<${#b[@]}; i++ )); do
echo -n "${b[i]}"
done
else
for (( i=m; i<${#a[@]}; i++ )); do
echo -n "${a[i]}"
done
fi
[编辑]
上面的脚本确实有效,但一点也不有趣。我重新考虑使用
paste
命令:
paste -d '' <(sed '/.\+/s/.\+/1:&/' file1 | tr '\n' '#' | sed 's/##/#\'$'\n/g') \
<(sed '/.\+/s/.\+/2:&/' file2 | tr '\n' '#' | sed 's/##/#\'$'\n/g') \
| tr -d '\n' | tr '#' '\n'
使用GNU-sed粘贴-d':
paste -z -d $'\n' <(
sed 's/^$/\x00/;t;s/^/1:/' file1.txt) <(
sed 's/^$/\x00/;t;s/^/2:/' file2.txt) |
sed 's/\x00//g;/^$/d'
paste-z-d$'\n'不清楚,请您在问题中提供更多细节,特别是获取样本输出的逻辑,请在完成后告诉我们。我添加了更多信息。问题非常好!但是,在没有awk的情况下这样做比使用awk更具挑战性awk@fangio,不应该持续2个B
s就像1:B
一样,因为只有1个B是连续的,如果我在这里错了,很抱歉。这是一个很好的例子,可以说明为什么awk是执行此类任务的合适工具++尝试使用cat
而不是粘贴!我为什么要这么做!我需要将file2.txt中的第二个“block”放在file1.txt中的第二个“block”之后。