循环外部的shellvariables设置在其外部

我正在试图find其中最多的字符的path名。 可能有更好的方法来做到这一点。 但是我想知道为什么会出现这个问题。

LONGEST_CNT=0 find samples/ | while read line do line_length=$(echo $line | wc -m) if [[ $line_length -gt $LONGEST_CNT ]] then LONGEST_CNT=$line_length LONGEST_STR=$line fi done echo $LONGEST_CNT : $LONGEST_STR 

它不知何故总是返回:

 0 : 

如果我在while循环中打印debugging结果,那么值是正确的。 那么为什么bash不会使这些variables成为全局的呢?

当你在Bash中进入一个while循环时,它会创build一个子shell。 当subshel​​l退出时,所有variables都返回到它们以前的值(可能为空或未设置)。 这可以通过使用进程replace来防止。

 LONGEST_CNT=0 while read -r line do line_length=${#line} if (( line_length > LONGEST_CNT )) then LONGEST_CNT=$line_length LONGEST_STR=$line fi done < <(find samples/ ) # process substitution echo $LONGEST_CNT : $LONGEST_STR 

丹尼斯给出了“正确的”答复。 但是,如果循环包含多行代码,我觉得这个过程replace技巧是非常不可读的。 阅读脚本时,我想先看看进入pipe道的内容,然后再看看它是如何处理的。

所以我通常更喜欢封装“{}”中的while循环。

 LONGEST_CNT=0 find /usr/share/zoneinfo | \ { while read -r line do line_length=${#line} if (( line_length > LONGEST_CNT )) then LONGEST_CNT=$line_length LONGEST_STR=$line fi done echo $LONGEST_CNT : $LONGEST_STR } 

关于find最长的path名。 这是一个替代scheme:

 find /usr/share/zoneinfo | while read line; do echo ${#line} $line done | sort -nr | head -n 1 # Result: 58 /usr/share/zoneinfo/right/America/Argentina/ComodRivadavia 

原谅我,如果这被认为是脱离主题,我希望它可以帮助别人。

做你总是(应该)做的事情:

  • 单独的担忧,
  • 避免全局,
  • logging你的代码,
  • 可读性强,
  • 也许是POSIXy。

(是的,我添加了一些比绝对必要的更多的“良好做法”成分))

所以我最喜欢的对隐形子壳问题的“膝盖反应”是使用函数:

 #!/bin/sh longest() { # # Print length and body of the longest line in STDIN # local cur_ln # current line local cur_sz # current size (line length) local max_sz # greatest size so far local winner # longest string so far max_sz=0 while read -r cur_ln do cur_sz=${#cur_ln} if test "$cur_sz" -gt "$max_sz"; then max_sz=$cur_sz winner=$cur_ln fi done echo "$max_sz" : "$winner" } find /usr/share/zoneinfo | longest # ok, if you really wish to use globals, here you go ;) LONGEST_CNT=0 LONGEST_CNT=$( find /usr/share/zoneinfo \ | longest \ | cut -d: -f1 \ | xargs echo\ ) echo "LONGEST_CNT='$LONGEST_CNT'" 

除了避免子shell的烦恼之外,它给你提供了完美的地方来logging代码,并且添加了namespacing:注意里面的函数可以使用更简短的variables名称,而不会丢失任何可读性。