2013-04-13 17 views
5

ich mehrere Strings in Schleife verketten müssen und das Ergebnis der Variablen zuweisen:Wie Strings mit printf in bash formatiert verketten

Formatierter String Beispiel:

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

Aus meiner Sicht sollte es so funktionieren:

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 

Aber es macht :(nicht

UPD:

Vollcodeliste unten:

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 
+3

** Immer ** stellen Sie sicher, dass der Code, den Sie in einer Frage eingeben, das Problem reproduziert, das Sie haben; Dein ursprünglicher Beitrag nicht. Der Grund dafür, dass 'result' leer ist, besteht darin, dass Sie ihm innerhalb einer Subshell zuweisen; Diese Änderungen verschwinden nach dem Beenden der Subshell. Aufgrund unserer ursprünglichen Frage konnten wir das nicht wissen. – chepner

+1

Auf eine andere Anmerkung - das ist erstaunlich schrecklichen Code. Sie sollten niemals die Ausgabe von "ls" auf diese Weise parsen; siehe http://mywiki.wooledge.org/ParsingLs für eine Erklärung warum - auch die 'Katze | Grep' dreimal für jede einzelne Zeile der Eingabe ist äußerst ineffizient. –

Antwort

7

doppelte Anführungszeichen um $ result und alle anderen Variablen, die Leerzeichen und andere Sonderzeichen enthalten können, wenn sie auf ein Programm als ein einziges Argument verwendet werden oder integrierte Funktion:

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

Wenn Sie wollen einfach nur das Ergebnis von printf einer variablen zugewiesen werden (wie Sie getan haben), können Sie auch

printf -v result '%s| %-15s| %-25s| %-15s| %-15s| %-15s\n' "$result" "$size" "$name" "$visits" "$inbound" "$outbound" 

BTW verwenden können: auch a + = Zuweisungsoperator, der gerade anhängt in Strings (siehe bash man-Seite, Abschnitt PARAMETERS).

In der vollständigen Code-Auflistung fehlt ein Pipe-Zeichen nach dem "fertig" vor dem zweiten "während ich lese".

Und wenn Sie

echo $result 

der Inhalt von $ result nennen ist schon verloren, da die printf in einem Teilprozess durch die Pipe-Zeichen nach erstellt genannt wird ‚do ich ...‘. Die übergeordneten Prozesse haben keinen Zugriff auf die (Umgebungs-) Variablen des Unterprozesses.

Ich würde lieber den Code etwas umschreiben wie

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" 

Der read < <(cmd) Ausdruck ist ähnlich cmd | read aber die ehemalige setzt den Befehl in dem Teilprozess statt, während die Lese im Hauptprozess ausgeführt wird. Auf diese Weise können die durch read gesetzten Variablen auch in nachfolgenden Befehlen verwendet werden.

+0

sieht es so aus, als wäre das Problem nicht in printf, sondern irgendwo in rohren und schleifen. Ich habe den vollständigen Quellcode hinzugefügt – user947668

+0

Ich habe die Antwort aktualisiert, die Hauptsache ist wahrscheinlich der Zugriff auf das Ergebnis env var aus dem obersten übergeordneten Prozess – Jacob

+0

Jacob, danke. Dein Code ist viel besser! – user947668

1

Ihr Code sieht nicht gut aus. Eine Sache, die Sie brauchen zu tun, da result Leerzeichen enthalten wird, wie Sie es hinzufügen, ist die Expansion zitieren:

result=$(printf '...' "$result" "$size" "$name" ...) 

die anderen Variablen Quoting nicht notwendig sein, aber es ist in der Regel eine gute Idee.

Fehler bei der Angabe $result sollten jedoch nicht dazu führen, dass es vollständig leer ist. Möglicherweise müssen Sie mehr Code in Ihrer while-Schleife veröffentlichen.

+0

Ich habe ein Beispiel für die Variable $ outbound hinzugefügt. Andere in printf verwendete Variablen sind ähnlich. Es gibt nichts anderes in der Schleife – user947668

+0

vollständigen Quellcode hinzugefügt. – user947668