Bash 读取文本文件,更改某些行的列顺序
我的输入文件的格式如下:Bash 读取文本文件,更改某些行的列顺序,bash,shell,awk,sed,Bash,Shell,Awk,Sed,我的输入文件的格式如下: 0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1 0 1 0 3/4 1 0 0 1/4 0 0 -1 1/2 0 -1 0 1/4 -1 0 0 3/4 0 0 1 1/2 我想重新排列包含分数的行的顺序。目前我有: #!bi
0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1
0 1 0 3/4 1 0 0 1/4 0 0 -1 1/2
0 -1 0 1/4 -1 0 0 3/4 0 0 1 1/2
我想重新排列包含分数的行的顺序。目前我有:
#!bin/bash
filename="input.txt"
while ((i++)); read -r line; do
re='[0-9][/][0-9]';
if [[ $line =~ $re ]]
then
echo $line
fi
done < "$filename"
这会使我的文件看起来像
0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
最好使用
awk
:
awk -v OFS='\t' '/[0-9]\/[0-9]/{print $1,$2,$3,$5,$6,$7,$9,$10,$11,$4,$8,$12; next} 1' file
0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
最好使用
awk
:
awk -v OFS='\t' '/[0-9]\/[0-9]/{print $1,$2,$3,$5,$6,$7,$9,$10,$11,$4,$8,$12; next} 1' file
0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
@阿努巴瓦是一个比我更好的解决方案。既然我写了另一段代码,我也会介意的
#!/bin/bash
filename="input.txt"
awk '
{
for (i=1; i <= NF; i++)
if ( $(i+1) == "/" || $i == "/" || $(i-1) == "/") {
printf "MM%sMM",$i" "$(i+1)" "$(i+2)
i = i+2
} else if ( match ($i, /^[[:digit:]]\/[[:digit:]]/) ) {
printf "MM%sMM",$i
} else {
printf "MM%sMM",$i
}
printf "\n"
}' $filename | sed -e 's/MMMM/MM/g;s/^MM//;s/MM/\t/g'
#/bin/bash
filename=“input.txt”
awk'
{
因为(i=1;i@anubhava是一个比我更好的解决方案。因为我写了其他代码,所以请记住
#!/bin/bash
filename="input.txt"
awk '
{
for (i=1; i <= NF; i++)
if ( $(i+1) == "/" || $i == "/" || $(i-1) == "/") {
printf "MM%sMM",$i" "$(i+1)" "$(i+2)
i = i+2
} else if ( match ($i, /^[[:digit:]]\/[[:digit:]]/) ) {
printf "MM%sMM",$i
} else {
printf "MM%sMM",$i
}
printf "\n"
}' $filename | sed -e 's/MMMM/MM/g;s/^MM//;s/MM/\t/g'
!/bin/bash
filename=“input.txt”
awk'
{
对于(i=1;i你可以很容易地用awk做到这一点,尽管如此,我认为稍微定义一下游戏规则是很重要的。
在下列假设下:
- 分数是以下形式的任意一种:
A/b
或A/b
或A/b
- 如果分数出现在第4列或第8列中,请重新排列这些列
- 您希望保持格式正确
考虑到这一点,您可以使用以下awk代码
awk 'BEGIN{format="%4s%6s%6s%6s%6s%6s%6s%6s%6s%7s%7s%7s\n"}
{ gsub(/[[:blank:]]*\/[[:blank:]]*/,"/",$0); $0=$0 }
($4 ~ /\//) || ($8 ~ /\//) {
$12=$4" "$8" "$12
$4=""; $8=""
$0=$0
}
{ printf format,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12 }
' file.txt
这样做的目的如下:
- 用单个
/
替换所有“/”
或其上的任何变体
$0=$0
重新定义字段,即在前两行中
将从18个字段移动到12个字段
- 如果在字段4或8中出现分数(即a
/
),则重新定义字段12,删除字段4和8,然后再次执行$0=$0
- 用正确的格式打印
注:在上述示例中,分数具有不同的输出(无空格)
以上内容将为您提供以下输出:
0 1 0 0 0 1 1 0 0 0/1 0/1 0/1
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
如果你不想改变第一行中的分数,那么你可以像这样做很容易
awk 'BEGIN{format="%4s%6s%6s%6s%6s%6s%6s%6s%6s%7s%7s%7s\n"}
(NF>12) { print; next }
{
$12=$4" "$8" "$12
$4=""; $8=""
$0=$0
printf format,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12
}
' file.txt
在这里,你假设
- 如果一行有超过12个字段,只需打印即可
- 否则,洗牌列
然而,这是不太可靠的,因为一切都取决于分数在第4、第8和第12列中的类型。也就是说,它们必须在没有空格的情况下键入。输出如下所示:
0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
你可以用awk轻松做到这一点,尽管如此,我认为定义一点游戏规则是很重要的。
在下列假设下:
- 分数是以下形式的任意一种:
A/b
或A/b
或A/b
- 如果分数出现在第4列或第8列中,请重新排列这些列
- 您希望保持格式正确
考虑到这一点,您可以使用以下awk代码
awk 'BEGIN{format="%4s%6s%6s%6s%6s%6s%6s%6s%6s%7s%7s%7s\n"}
{ gsub(/[[:blank:]]*\/[[:blank:]]*/,"/",$0); $0=$0 }
($4 ~ /\//) || ($8 ~ /\//) {
$12=$4" "$8" "$12
$4=""; $8=""
$0=$0
}
{ printf format,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12 }
' file.txt
这样做的目的如下:
- 用单个
/
替换所有“/”
或其上的任何变体
$0=$0
重新定义字段,即在前两行中
将从18个字段移动到12个字段
- 如果在字段4或8中出现分数(即a
/
),则重新定义字段12,删除字段4和8,然后再次执行$0=$0
- 用正确的格式打印
注:在上述示例中,分数具有不同的输出(无空格)
以上内容将为您提供以下输出:
0 1 0 0 0 1 1 0 0 0/1 0/1 0/1
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
如果你不想改变第一行中的分数,那么你可以像这样做很容易
awk 'BEGIN{format="%4s%6s%6s%6s%6s%6s%6s%6s%6s%7s%7s%7s\n"}
(NF>12) { print; next }
{
$12=$4" "$8" "$12
$4=""; $8=""
$0=$0
printf format,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12
}
' file.txt
在这里,你假设
- 如果一行有超过12个字段,只需打印即可
- 否则,洗牌列
然而,这是不太可靠的,因为一切都取决于分数在第4、第8和第12列中的类型。也就是说,它们必须在没有空格的情况下键入。输出如下所示:
0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1
0 1 0 1 0 0 0 0 -1 3/4 1/4 1/2
0 -1 0 -1 0 0 0 0 1 1/4 3/4 1/2
@阿努巴瓦编辑了哈!:-)我知道,我只是想用一种更好的方式来描述我的问题,这可能会让事情变得更糟。我开始认为我无法解决这个问题,只能手动更改所有行,用哪个字符分隔列?这些行是否包含前导分隔符?@anubhava editedHah!:-)我知道,我只是想用一种更好的方式来描述我的问题,这可能会让事情变得更糟。我开始认为我无法解决这个问题,只能手动更改所有行,用哪个字符分隔列?行中是否包含前导分隔符?@RobS。如果你有现代版的gawk yo你可以就地更换(参考)。只需将awk
替换为gawk-i inplace
。如果您的awk版本不支持inplace,那么您可以执行awk'…'file.txt>file.new.txt;mv file.new.txt file.txt
。基本上是创建一个新文件并重命名它。gawk不起作用,但简单地将输出写入一个新文件并移动该文件即可。大大提高了感谢您的帮助!@RobS。如果您有现代版的gawk,您可以就地更换(参考)。只需将awk
替换为gawk-i inplace
。如果您的awk版本不支持inplace,那么您可以执行awk'…'file.txt>file.new.txt;mv file.new.txt file.txt
。基本上是创建一个新文件并重命名它。gawk不起作用,但简单地将输出写入一个新文件并移动该文件即可。大大提高了感谢帮助!它没有,分数保留在行内。但是找到了一个解决方案。它是否与所示的预期输出匹配?它没有,分数保留在行内。但是找到了一个解决方案。它是否与所示的预期输出匹配?