基本上我所拥有的是一个文本文件(file.txt),它包含数字行(行不一定是相同的长度),例如。
1 2 3 4
5 6 7 8
9 10 11 12 13
我需要做的是编写新文件,删除每个号码,一次删除一个,例如更换第一个新文件将包含
2 3 4< ---第1个元素被移除
5 6 7 8
9 10 11 12 13
并且第7个文件将包含
1 2 3 4
在此处移除了5 6 8 <---第7个元素
9 10 11 12 13
为了生成这些,我循环遍历每一行,然后遍历每一行中的每个元素。例如。对于第7个文件,我删除第二行的第三个元素,我试图通过读取行,删除相应的元素,然后重新插入这个新行
$ lineNo是2(第二行)
$ line是5 6 7 8
有了剪切,我删除第三个号码,制作$ newline 5 6 8
然后我尝试用$ newline使用sed替换file.txt中的$ lineNo行:
sed -n'$ lineNo s /.*/'$ newline'/'&gt; file.txt的
这完全不起作用。我收到一个错误
sed:无法读取25.780000:没有这样的文件或目录
(其中25.780000是我的文本文件中的数字。看起来它正在尝试使用$ newline来读取文件或其他内容)
我有理由怀疑我说明要替换的哪条线路不起作用:(
我的问题是,a)有没有更好的方法来做到这一点而不是sed,b)如果sed是要走的路,我做错了什么?
谢谢!
答案 0 :(得分:3)
filename=file.txt
i=1
while [[ -s $filename ]]; do
new=file_$i.txt
awk 'NR==1 {if (NF==1) next; else sub(/^[^ ]+ /, "")} 1' $filename > $new
((i++))
filename=$new
done
这会在每个新文件的第一行的开头留一个空格,当一行变空时,该行将被删除。当最后生成的文件为空时,循环结束。
更新:
words=$(wc -w < file.txt)
for ((i=1; i<=words; i++)); do
awk -v n=$i '
words < n && n <= words+NF {$(n-words) = "" }
{words += NF; print}
' file.txt > file_$i.txt
done
答案 1 :(得分:3)
除非我误解了这个问题,否则以下内容应该有效,但如果你的文件很大,它会很慢:
#! /bin/bash
remove_by_value()
{
local TO_REMOVE=$1
while read line; do
out=
for word in $line; do [ "$word" = "$TO_REMOVE" ] || out="$out $word"; done
echo "${out/ }"
done < $2
}
remove_by_position()
{
local NTH=$1
while read line; do
out=
for word in $line; do
((--NTH == 0)) || out="$out $word"
done
echo "${out/ }"
done < $2
}
FILE=$1
shift
for number; do
echo "Removing $number"
remove_by_position $number "$FILE"
done
这会将所有输出转储到stdout,但更改它应该是微不足道的,因此每个删除的数字的输出都会被重定向(例如,使用remove_by_position $number $FILE > $FILE.$$ && mv $FILE.$$ $FILE.$number
并正确引用)。运行它,比方说,
$ bash script.sh file.txt $(seq 11)
答案 2 :(得分:1)
我不得不承认,我对其他解决方案的简短有点惊讶。
#!/bin/bash
#
file=$1
lines=$(cat $file | wc -l)
out=0
dropFromLine () {
file=$1
row=$2
to=$((row-1))
from=$((row+1))
linecontent=($(sed -n "${row}p" $file))
# echo " linecontent: " ${linecontent[@]}
linelen=${#linecontent[@]}
# echo " linelength: " $linelen
for n in $(seq 0 $linelen)
do
(
if [[ $row > 1 ]] ; then sed -n "1,${to}p" $file ;fi
for i in $(seq 0 $linelen)
do
if [[ $n != $i ]]
then
echo -n ${linecontent[$i]}" "
fi
done
echo
# echo "mod - drop " ${linecontent[$n]}
sed -n "$from,${lines}p" $file
) > outfile-${out}.txt
out=$((out+1))
done
}
for row in $(seq 1 $lines)
do
dropFromLine $file $row
done
调用:
./dropFromRow.sh num.dat
num.dat:
1 2 3 4
5 6 7 8
9 10 11
结果:
outfile-0 outfile-10 outfile-12 outfile-2 outfile-4 outfile-6 outfile-8
outfile-1 outfile-11 outfile-13 outfile-3 outfile-5 outfile-7 outfile-9
样品:
asux:~/proj/mini/forum > cat outfile-0
2 3 4
5 6 7 8
9 10 11
asux:~/proj/mini/forum > cat outfile-1
1 3 4
5 6 7 8
9 10 11
答案 3 :(得分:0)
使用perl
的一种方式:
file.txt
的内容:
1 2 3 4
5 6 7 8
9 10 11 12 13
script.pl
的内容:
use warnings;
use strict;
## Read all input to a scalar variable as a single string.
my $str;
{
local $/ = undef;
$str = <>;
}
## Loop for each number found.
while ( $str =~ m/(\d+)(?:\h*)?/g ) {
## Open file for writing. The name of the file will be
## the number matched in previous regexp.
open my $fh, q[>], ($1 . q[.txt]) or
die qq[Couldn't create file $1.txt\n];
## Print everything prior to matched string plus everything
## after matched string.
printf $fh qq[%s%s], $`, $';
## Close file.
close $fh;
}
像以下一样运行:
perl script.pl file.txt
显示已创建的文件:
ls [0-9]*.txt
输出:
10.txt 11.txt 12.txt 13.txt 1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt 8.txt 9.txt
显示其中一个的内容:
cat 9.txt
输出:
1 2 3 4
5 6 7 8
10 11 12 13