将命令的输出分配给shell变量并获取变量大小

时间:2011-04-27 09:51:24

标签: file shell awk grep

我有一个由数字组成的文件。通常,每行包含一个数字。我想计算文件中以数字'0'开头的行数。如果是这样,那么我想做一些后期处理。

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

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});

根据0中找到的以${inputFile}开头的行号,我想从${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删除行3${anotherFile},因为这些行对应{{1}中以0开头的行}}

5 个答案:

答案 0 :(得分:1)

我认为您必须执行以下操作来分配数组:

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

要获得元素的数量(就像在注释行中一样):

linesNr=${#linesToRemove[@]}

要删除文件中的行,您可以执行以下操作:

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

答案 1 :(得分:1)

如果要计算文件中以0开头的行数,则该行是错误的。

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&amp;&amp; / ^ 0 /表示处理第一个文件整行以0开头并将其行号放入数组aNR>FNR表示处理下一个文件,如果行号不在数组中,则打印该行。有关FNR,NR等的含义,请参阅gawk文档

答案 2 :(得分: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>

答案 3 :(得分: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'。)

答案 4 :(得分:0)

鉴于此问题的大量编辑,开始一个新答案似乎最容易。您的问题可以通过一个简单的单行解决:

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