我正在尝试找到其中包含最多字符的路径名。可能有更好的方法来做到这一点。但我想知道为什么会出现这个问题。
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循环中打印调试结果,则值是正确的。那么为什么bash不能使这些变量全局化呢?
答案 0 :(得分:74)
当您在Bash中输入while
循环时,它会创建一个子shell。子shell退出时,所有变量都返回其先前的值(可以为null或未设置)。这可以通过使用进程替换来防止。
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
答案 1 :(得分:20)
“正确”回复由Dennis给出。但是,如果循环包含多行,我发现进程替换技巧极不可读。在阅读脚本时,我希望在看到它如何处理之前看到管道中的内容。
所以我通常更喜欢在“{}”中封装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
}
答案 2 :(得分:2)
关于找到最长的路径名。这是另一种选择:
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
请原谅我,如果这被认为是偏离主题,我希望它可以帮助某人。
答案 3 :(得分:1)
做你应该做的事情:
(是的,我添加了更多的&#34;良好的做法&#34;汤的成分超过绝对必要;)
所以我最喜欢的&#34;膝跳反应&#34;对隐形子shell的问题是使用函数:
#!/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烦恼之外,它还为您提供了记录代码的完美位置,并且排序添加了命名空间:请注意,在函数内部,您可以使用更短更简单的变量名,而不会丢失任何可读性。