如何在bash中连接用printf格式化的字符串

use*_*668 7 bash shell printf

我需要在循环中连接几个字符串并将结果赋值给变量:

格式化字符串示例:

result=$(printf '| %-15s| %-25s| %-15s| %-15s| %-15s\n' $size $name $visits $inbound $outbound);
Run Code Online (Sandbox Code Playgroud)

从我的角度来看,它应该像这样工作:

result=''
while read somevar
do
    ...
    outbound=`cat "$www_path/$name/access.log"|grep \`date +"%d/%b/%Y"\`|awk '{ sum+=$11} END {print sum/1024/1024}'`
    result=$(printf '%s| %-15s| %-25s| %-15s| %-15s| %-15s\n' $result $size $name $visits $inbound $outbound);
    ...
done
echo $result
Run Code Online (Sandbox Code Playgroud)

但它没有:(

UPD:

完整代码列表如下:

www_path='/var/www';
result='';
cd /var/www/; ls -d */ | while read i ; do basename "$i" ; done
while read i;
do du -sh "$i"|
        while read size name
        do
                visits=`cat "$www_path/$name/access.log"|grep \`date +"%d/%b/%Y"\`|grep -v "internal dummy connection"|awk -F ' ' '{print $1}'  | sort | uniq | wc -l|tr '\n' '\t'|sed 's/$/\t/'`
                inbound=`cat "$www_path/$name/access.log"|grep \`date +"%d/%b/%Y"\`|grep -v "internal dummy connection"|awk '{ sum+=$10} END {print sum/1024/1024}'|tr '\n' '\t'|sed  's/$/\t\t/'`
                outbound=`cat "$www_path/$name/access.log"|grep \`date +"%d/%b/%Y"\`|grep -v "internal dummy connection"|awk '{ sum+=$11} END {print sum/1024/1024}'`;
                result=$(printf '%s| %-15s| %-25s| %-15s| %-15s| %-15s\n' "$result" "$size" "$name" "$visits" "$inbound" "$outbound")
        done
done
echo $result
Run Code Online (Sandbox Code Playgroud)

Jac*_*cob 12

在$ result和所有其他可能包含空格和其他特殊字符的变量周围使用双引号,如果它们要用作程序或内置函数的单个参数:

result=$(printf '%s| %-15s| %-25s| %-15s| %-15s| %-15s\n' "$result" "$size" "$name" "$visits" "$inbound" "$outbound")
Run Code Online (Sandbox Code Playgroud)

如果您只想将printf的结果分配给变量(就像您所做的那样),您也可以使用

printf -v result '%s| %-15s| %-25s| %-15s| %-15s| %-15s\n' "$result" "$size" "$name" "$visits" "$inbound" "$outbound"
Run Code Online (Sandbox Code Playgroud)

顺便说一句:还有一个+ =赋值运算符,只是追加到字符串(参见bash手册页,PARAMETERS部分).

在完整的代码清单中,在第二个"读取i"之前的"完成"之后缺少管道符号.

当你打电话的时候

echo $result
Run Code Online (Sandbox Code Playgroud)

$ result的内容已经丢失,因为printf是在'do du ...'之后由管道符号创建的子进程中调用的.父进程无法访问子进程的(环境)变量.

我宁愿把代码改写成类似的东西

result=""
for name in /var/www/* ; do 
    read size __ < <(du -sh "$name")
    name=${name##*/}
    #insert the other stuff here and add arguments to printf
    printf -v line '| %-15s| %-25s\n' "$size" "$name"
    result+=$line
done
echo "$result"
Run Code Online (Sandbox Code Playgroud)

read < <(cmd)表达式类似于cmd | read但在子过程前者放命令代替,而读在主处理中执行.这样,read设置的变量也可以用在后续命令中.