2011-04-27 114 views
1

我有一个由数字组成的文件。通常,每行包含一个单一的数字。我想要统计文件中以数字“0”开头的行数。如果是这样的话,那么我想做一些后期处理。将命令的输出分配给shell变量并获取变量大小

虽然我能够正确检索相应的行号,但检索行的总数不正确。下面,我发布我正在使用的代码。

linesToRemove=$(awk '/^0/ { print NR; }' ${inputFile}); 
# linesToRemove=$(grep -n "^0" ${inputFile} | cut -d":" -f1); 

linesNr=${#linesToRemove} # <- here, the error 
# linesNr=${#linesToRemove[@]} # <- here, the error 

if [ "${linesNr}" -gt "0" ]; then 
    # do something here, e.g. remove corresponding lines. 
    awk -v n=$linesToRemove 'NR == n {next} {print}' ${anotherFile} > ${outputFile} 
fi 

另外,至于基于awk的命令,我怎样才能使用shell变量?我尝试了下面的命令,但它不能正常工作,因为'myIndex'被解释为文本而不是变量。

linesToRemove=$(awk -v myIndex="$myIndex" '/^myIndex/ { print NR;}' ${inputFile}); 

考虑开始与${inputFile}发现0行号,我想从${anotherFile}删除相应的行号。两个$ {INPUTFILE} $ {anotherFile}下面给出一个例子,:

// ${inputFile} 
0 
1 
3 
0 

// ${anotherFile} 
2.617300e+01 5.886700e+01 -1.894697e-01 1.251225e+02 
5.707397e+01 2.214040e+02 8.607959e-02 1.229114e+02 
1.725900e+01 1.734360e+02 -1.298053e-01 1.250318e+02 
2.177940e+01 1.249531e+02 1.538853e-01 1.527150e+02 

// ${outputFile} 
5.707397e+01 2.214040e+02 8.607959e-02 1.229114e+02 
1.725900e+01 1.734360e+02 -1.298053e-01 1.250318e+02 

在上面的例子中,我需要删除线0和从${anotherFile}3,因为这些行对应于开头的行0 in ${inputFile}

回答

1

,那么这行是错误的。

linesToRemove=$(awk '/^0/ { print NR; }' ${inputFile});

上述表示打印行数时行从0开始,你的linesToRemove变量将包含所有的行号,而不是行的总数。使用END{}块来捕获总数。例如

linesToRemove=$(awk '/^0/ {c++}END{print c}' ${inputFile});

至于使用awk的内部变量您的第二个问题,使用正则表达式运算符~。然后设置你的myIndex变量包括^

linesToRemove=$(awk -v myIndex="^$myIndex" '$0 ~ myIndex{ print NR;}' ${inputFile});

最后,如果你只是想删除那些以0开头的行,那么就干脆删除它

awk '/^0/{next}{print $0>FILENAME}' file 

如果你想使用输入文件中捕获的内容从另一个文件中删除行,这里有一种方法

paste -d"|" inputfile anotherfile | awk '!/^0/{gsub(/^.*\|/,"");print}' 

或者只是一个awk命令

awk 'FNR==NR && /^0/{a[FNR]} NR>FNR && (!(FNR in a))' inputfile anotherfile 

粗解释:FNR == NR & &/^ 0 /装置处理的第一个文件整个行开头0,并把它的行号到数组aNR>FNR表示处理下一个文件,如果行号不在数组中,则打印该行。请参阅gawk文档了解FNR,NR等的含义

+0

@ ghosdog74,谢谢!实际上,最终目标是从一个文件中检索以0开头的行,然后从另一个文件中删除相应的行。此外,是否有可能使用变量'linesToRemove'的大小/长度来查找总行数? – Javier 2011-04-27 12:38:10

+0

@Javier,你应该发布这些文件的样本,并显示你的最终输出。我可以更好地向你展示,如果不是比你现在正在做的更有效的方式 – ghostdog74 2011-04-27 12:45:58

+0

@ ghosdog74,我更新了这篇文章,并包含了这两个文件的一些示例。 – Javier 2011-04-27 12:56:32

0

一般来说,如果你这样做:

linesToRemove=$(awk '/^0/ { print NR; }' ${inputFile}); 

,而不是这样的:

linesToRemove=$(awk '/^0/ { print NR; }' ${inputFile}); 
linesNr=${#linesToRemove} 

使用本:

linesToRemove=$(awk '/^0/ { print NR; }' ${inputFile}); 
linesNr=${echo $linesToRemove|awk '{print NF}'} 

POC:

cat temp.sh 
#!/usr/bin/ksh 

lines=$(awk '/^d/{print NR}' script.sh) 
nooflines=$(echo $lines|awk '{print NF}') 
echo $nooflines 
torinoco!DBL:/oo_dgfqausr/test/dfqwrk12/vijay> temp.sh 
8 
torinoco!DBL:/oo_dgfqausr/test/dfqwrk12/vijay> 
+0

“换行换行标签”?并非如此。如果你不能“引用”这个变量,那么你的变量会受到shell分词(http://wiki.bash-hackers.org/syntax/expansion/wordsplit) – 2011-04-27 11:12:54

+0

哦,你是正确的删除它。 – Vijay 2011-04-27 11:46:04

1

我认为你必须做到以下几点指定数组:

linesToRemove=($(awk '/^0/ { print NR; }' ${inputFile})) 

而获得的元素数量做(因为你有一个注释行):

linesNr=${#linesToRemove[@]} 

要删除行从该文件,你可以这样做:如果你想数以0开头的文件中的行数

sedCmd="" 
for lineNr in ${linesToRemove[@]}; do 
    sedCmd="$sedCmd;${lineNr}d" 
done 
sed "$sedCmd" ${anotherFile} > ${outputFile} 
+0

谢谢!通过在'linesToRemove'数组中以'0'开始的行号,我怎样才能用它从文件中删除这些行号? – Javier 2011-04-27 12:25:23

+0

@Javier:我使用'd'(delete)命令为'sed'命令添加了一个示例。 – bmk 2011-04-27 13:24:36

+0

谢谢!有没有办法加快代码?我有几个文件需要处理,并且执行上面的代码只有一个文件需要一些时间。 – Javier 2011-04-27 13:51:49

0

它很大程度上取决于您正在进行的后处理,但是您是否真的需要实际计数?为什么不这样做:

 
if grep ^0 $inputfile > /dev/null; then 
    # There is at least one line with a leading 0 
    : 
fi 

grep -v ^0 $inputfile | process-lines-without-leading-zero 
grep ^0 $inputfile | process-lines-with-leading-zero 

或者,哪怕只是:

 
if grep ^0 $inputfile | process-lines-with-leading-zero; then 
    # some post processing 
    : 
fi 

- 编辑 -

根据你已经在您的评论说,我会建议不同的方法。如果我理解正确,您想读取文件a,查找表格^ 0 [0-9] *, 的行,然后从文件b中删除这些行号。如果文件变大,一次只做一行很慢。只要这样做:

 
cmd=$(grep '^0[0-9]*$' a | sed 's/$/d;/g') 
sed "$cmd" b 

对cmd的赋值形成一个sed命令来删除这些行。在b上调用sed将省略这些行。您需要适当地重定向sed输出(也许是临时文件,然后回到b,或者如果您使用的是gnu sed,只需使用'sed -i')。

+0

谢谢!实际上,我需要做的是首先找到文件“A”中以'0'开头的行,然后从文件'B'中删除这些行。我更新了原始文章并插入了用于删除检索到的行的命令。 – Javier 2011-04-27 12:36:46

+0

@javier。如果没有行匹配,则cmd为空,最终的sed为空操作,并且b将保持不变。 – 2011-04-27 13:38:11

+0

我调用了'cmd = $(grep'^ 0 [0-9] * $'$ {inputFile}'后,得到以下消息:'sed:-e expression#1,char 2: | sed's/$/d;/g')'然后是'sed'$ cmd“$ {anotherFile}' – Javier 2011-04-27 13:39:18

0

由于大量的编辑这个问题,似乎最容易开始一个新的答案。你的问题可以用一个简单的单行来解决:

 
$ sed "$(grep -n ^0 $inputFile | sed 's/:.*/d;/g')" $anotherFile > $outputFile 
相关问题