【问题标题】:Return two variables in awk在 awk 中返回两个变量
【发布时间】:2012-01-25 11:07:08
【问题描述】:

这就是我正在做的事情

ret=$(ls -la | awk '{print $3 " "  $9}')
usr=$(echo $ret | awk '{print $1}')
fil=$(echo $ret | awk '{print $2}')

问题是我没有运行ls我运行的命令需要时间,所以你可以理解逻辑。

有没有办法可以设置返回值来设置两个外部值,比如

ls -la | awk -r usr=x -r fil=y '{x=$3; y=$9}'

这样命令将运行一次,我可以将其最小化为一行

【问题讨论】:

  • 解析ls应该处死。 mywiki.wooledge.org/ParsingLs
  • 就像我说的那样,我实际上并没有解析ls,它只是作为一个例子来说明我的观点。对不起,我没有说清楚

标签: bash shell awk


【解决方案1】:

它并不漂亮,但如果你真的需要在一行中完成这项工作,你可以使用awk/bash 的高级元编程功能:)

eval $(ls -la | awk '{usr = $3 " " usr;fil = $9 " " fil} END{print "usr=\""usr"\";fil=\""fil"\""}')

打印:

echo -e $usr
echo -e $fil

就我个人而言,我会坚持你所拥有的 - 与上述相比,它更具可读性并且性能开销很小:

$time <three line approach>

real    0m0.017s
user    0m0.006s
sys     0m0.011s

$time <one line approach>
real    0m0.009s
user    0m0.004s
sys     0m0.007s

【讨论】:

  • +1 非常好的方法。但是我们如何更新您的代码以允许$usr$fil 包含所有用户和所有文件名的列表? (这个第一个版本只给出了最后一个用户/文件名)。
  • 嗨@bob,我刚刚更改了您的代码以捕获所有用户/文件,而不仅仅是最后一对。拜托,你能再次执行你的基准测试吗?现在,时间结果应该是可比的......
  • 谢谢 - 误解了原来的要求!已根据 oHessling 的出色编辑进行了更新(稍作调整)。干杯!
【解决方案2】:

使用read 的解决方法

usr=""
fil=""
while read u f; do usr="$usr\n$u"; fil="$fil\n$f"; done < <(ls -la | awk '{print $3 " "  $9}')

对于性能问题,您可以使用&lt;&lt;&lt;,但如果返回的文本很大,请避免使用:

while read u f; do usr="$usr\n$u"; fil="$fil\n$f"; done <<< $(ls -la | awk '{print $3 " "  $9}')

受@WilliamPursell 回答启发的更便携的方式:

$ usr=""
$ fil=""
$ while read u f; do usr="$usr\n$u"; fil="$fil\n$f"; done << EOF
> $(ls -la | awk '{print $3 " "  $9}')
> EOF

【讨论】:

  • 天啊,非常聪明的想法。谢谢:D
  • 我还是更喜欢这种方式,谢谢
【解决方案3】:

您想要做的是捕获 ls 或任何其他命令的输出,然后再进行处理。

ls=$(ls -l)
first=$(echo $ls | awk '{print $1}')
second=$(echo $ls | awk '{print $2}')

【讨论】:

    【解决方案4】:

    使用bash v4 关联数组

    unset      FILES
    declare -A FILES
    FILES=( ls -la | awk '{print $9 " "  $3}' )
    

    打印所有者和文件列表:

    for fil in ${!FILES[@]}
    do
      usr=${FILES["$fil"]}
      echo -e "$usr" "\t" "$fil"
    done
    

    抱歉,我无法在我的电脑上进行测试,因为我的 bash v3.2 不支持 关联数组 :-(。 请报告任何问题...

    【讨论】:

      【解决方案5】:

      接受的答案使用进程替换,这是一种仅适用于某些平台的 bashism。更便携的解决方案是使用heredoc:

      读 u f

      尝试一下很诱人:

      我... |读你

      但是读取然后在子shell中运行。一种常见的技术是:

      我... | {读你f; # 在这里使用 $u 和 $f; }

      但要使变量在脚本的其余部分中可用,插值的 heredoc 是最便携的方法。请注意,它需要 shell 将程序的所有输出读取到内存中,因此如果预期输出很大或进程运行时间很长,则不适合。

      【讨论】:

      • +1 是的,你是对的 => 我已经完成了我的回答。谢谢;-)
      【解决方案6】:

      您可以使用 bash 数组或位置参数作为临时存放位置:

      ret_ary=( $(command | awk '{print $3, $9}') )
      usr=${ret_ary[0]}
      fil=${ret_ary[1]}
      
      set -- $(command  | awk '{print $3, $9}')
      usr=$1
      fil=$2
      

      【讨论】:

      • 最优雅的解决方案s,使用setarray[]
      猜你喜欢
      • 1970-01-01
      • 2022-01-04
      • 1970-01-01
      • 1970-01-01
      • 2018-03-26
      • 2014-11-19
      • 2013-11-13
      • 1970-01-01
      • 2013-02-28
      相关资源
      最近更新 更多