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

发布于 2024-11-03 10:38:52 字数 1443 浏览 4 评论 0原文

我有一个由数字组成的文件。通常,每一行包含一个数字。我想计算文件中以数字“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});

鉴于在 ${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

在上面的示例中,我需要从 ${ 中删除行 03 anotherFile},假设这些行对应于 ${inputFile} 中以 0 开头的行。

I have a file consisting of digits. Usually, each line contains one single number. I would like to count the number of lines in the file that begin with digit '0'. If it's the case, then I would like to do some post-processing.

Although I'm able to retrieve correctly the corresponding line numbers, the total number of retrieved lines is not correct. Below, I'm posting the code that I'm using.

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

Also, as for the awk-based command, how could I use a shell-variable? I tried the command below, but it's not working correctly, since 'myIndex' is interpreted as a text and not as a variable.

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

Given the line numbers starting with 0 found in ${inputFile}, I would like to remove the corresponding lines numbers from ${anotherFile}. An example for both ${inputFile} and ${anotherFile} is given below:

// ${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

In the example above, I need to delete lines 0 and 3 from ${anotherFile}, given that those lines correspond to the lines starting with 0 in ${inputFile}.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

朮生 2024-11-10 10:38:53

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

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

Given the large number of edits to this question, it seems easiest to start a new answer. Your problem can be solved with a simple one-liner:

$ sed "$( grep -n ^0 $inputFile | sed 's/:.*/d;/g' )" $anotherFile > $outputFile
把时间冻结 2024-11-10 10:38:52

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

If you want to count the number of lines in the file that begins with 0, then this line is wrong.

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

The above says to print the line number when the line start with 0, and your linesToRemove variable will contain all the line numbers, not the total number of lines. Use END{} block to capture the total. eg

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

As for your 2nd question on using variable inside awk, use the regex operator ~. And then set your myIndex variable to include the ^ anchor

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

finally, if you just want to remove those lines that start with 0, then just simply remove it

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

If you want to remove lines from another file using what is captured in input file, here's one way

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

Or just one awk command

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

crude explanation: FNR==NR && /^0/ means process the first file whole line starts with 0 and put its line number into array a. NR>FNR means process the next file and if line number not in array, print the line. See the gawk documentation for what FNR,NR etc means

冷夜 2024-11-10 10:38:52

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

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

并获取元素数量(如注释行中所示):

linesNr=${#linesToRemove[@]}

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

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

I think you have to do the following to assign an array:

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

And to get the number of elements do (as you have in a commented line):

linesNr=${#linesToRemove[@]}

To remove the lines from from the file you could do something like:

sedCmd=""
for lineNr in ${linesToRemove[@]}; do
  sedCmd="$sedCmd;${lineNr}d"
done
sed "$sedCmd" ${anotherFile} > ${outputFile}
避讳 2024-11-10 10:38:52

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

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>

In general if you do this:

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

instead of this:

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

use this:

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>
弥繁 2024-11-10 10:38:52

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

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]*

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

a | sed 's/$/d;/g' ) sed "$cmd" b

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

It greatly depends on the post-processing you are doing, but do you really need the actual count? Why not do something like this:

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

Or, even just:

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

--EDIT--

Based on what you've said in your comment, I would recommend a different approach. If I understand you correctly, you want to read file a, looking for lines of the form ^0[0-9]*,
and then remove those line numbers from file b. Doing it one line at a time is pretty slow if the files get big. Just do:

cmd=$( grep '^0[0-9]*

The assignment to cmd forms a sed command to delete the lines. Invoking sed on b will omit those lines. You'll need to redirect the sed output appropriately (perhaps to a temp file and then back to b, or just use 'sed -i' if you're using gnu sed.)

a | sed 's/$/d;/g' ) sed "$cmd" b

The assignment to cmd forms a sed command to delete the lines. Invoking sed on b will omit those lines. You'll need to redirect the sed output appropriately (perhaps to a temp file and then back to b, or just use 'sed -i' if you're using gnu sed.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文