[bash] laatste newline valt weg

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • MisterE
  • Registratie: April 2002
  • Laatst online: 01-10 18:56
ik kijk vast over iets heel simpels heen, maargoed.
Ik probeer mijn "echo's" te vervangen voor "printf's" zoals POSIX aangeeft.

ik heb een bestand met 4 regels:
code:
1
2
3
4
# status,date,version_engine,version_script
# status values: 0=valid, 1=invalid, 2=manually verified/ignore
1,2012-08-01 (13:37),0.9,0.9
0,2012-08-03 (18:37),1.0,1.0


Zoals hieronder te zien is heeft deze 4 newlines (\n)
Maar zodra ik deze in variabele file_lines lees heeft die er volgens "wc" nog maar 3.
Waarom zet ie de laatste newline niet in de variabele?

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
ikke@laptop:~/bin/log$ od -c status.cfg 
0000000   #       s   t   a   t   u   s   ,   d   a   t   e   ,   v   e
0000020   r   s   i   o   n   _   e   n   g   i   n   e   ,   v   e   r
0000040   s   i   o   n   _   s   c   r   i   p   t  \n   #       s   t
0000060   a   t   u   s       v   a   l   u   e   s   :       0   =   v
0000100   a   l   i   d   ,       1   =   i   n   v   a   l   i   d   ,
0000120       2   =   m   a   n   u   a   l   l   y       v   e   r   i
0000140   f   i   e   d   /   i   g   n   o   r   e  \n   1   ,   2   0
0000160   1   2   -   0   8   -   0   1       (   1   3   :   3   7   )
0000200   ,   0   .   9   ,   0   .   9  \n   0   ,   2   0   1   2   -
0000220   0   8   -   0   3       (   1   8   :   3   7   )   ,   1   .
0000240   0   ,   1   .   0  \n
0000246



ikke@laptop:~/bin/log$ cat status.cfg | wc -l
4


ikke@laptop:~/bin/log$ file_lines=$(cat status.cfg)


ikke@laptop:~/bin/log$ printf "$file_lines" | wc -l
3

Acties:
  • 0 Henk 'm!

  • FitzJac
  • Registratie: November 2010
  • Laatst online: 20:12
code:
1
file_lines=$(cat status.cfg|wc -l)

code:
1
printf "$file_lines"

Acties:
  • 0 Henk 'm!

  • CyBeR
  • Registratie: September 2001
  • Niet online

CyBeR

💩

(jarig!)
Ik vermoed dat dat gebeurt omdat 'echo' normaal gesproken (tenzij met -n) een newline achteraan zet, en door die laatste newline niet mee te nemen voorkomen wordt dat er een dubbele newline ontstaat.

Dit werkt:
printf "%s\n" "$blah"


Ziehier:
$ wc -l foofile 
       4 foofile
$ blah=$(cat foofile)
$ echo -n "$blah" | hexdump -C
00000000  23 20 73 74 61 74 75 73  2c 64 61 74 65 2c 76 65  |# status,date,ve|
00000010  72 73 69 6f 6e 5f 65 6e  67 69 6e 65 2c 76 65 72  |rsion_engine,ver|
00000020  73 69 6f 6e 5f 73 63 72  69 70 74 0a 23 20 73 74  |sion_script.# st|
00000030  61 74 75 73 20 76 61 6c  75 65 73 3a 20 30 3d 76  |atus values: 0=v|
00000040  61 6c 69 64 2c 20 31 3d  69 6e 76 61 6c 69 64 2c  |alid, 1=invalid,|
00000050  20 32 3d 6d 61 6e 75 61  6c 6c 79 20 76 65 72 69  | 2=manually veri|
00000060  66 69 65 64 2f 69 67 6e  6f 72 65 0a 31 2c 32 30  |fied/ignore.1,20|
00000070  31 32 2d 30 38 2d 30 31  20 28 31 33 3a 33 37 29  |12-08-01 (13:37)|
00000080  2c 30 2e 39 2c 30 2e 39  0a 30 2c 32 30 31 32 2d  |,0.9,0.9.0,2012-|
00000090  30 38 2d 30 33 20 28 31  38 3a 33 37 29 2c 31 2e  |08-03 (18:37),1.|
000000a0  30 2c 31 2e 30                                    |0,1.0|
000000a5
$ echo "$blah" | hexdump -C
00000000  23 20 73 74 61 74 75 73  2c 64 61 74 65 2c 76 65  |# status,date,ve|
00000010  72 73 69 6f 6e 5f 65 6e  67 69 6e 65 2c 76 65 72  |rsion_engine,ver|
00000020  73 69 6f 6e 5f 73 63 72  69 70 74 0a 23 20 73 74  |sion_script.# st|
00000030  61 74 75 73 20 76 61 6c  75 65 73 3a 20 30 3d 76  |atus values: 0=v|
00000040  61 6c 69 64 2c 20 31 3d  69 6e 76 61 6c 69 64 2c  |alid, 1=invalid,|
00000050  20 32 3d 6d 61 6e 75 61  6c 6c 79 20 76 65 72 69  | 2=manually veri|
00000060  66 69 65 64 2f 69 67 6e  6f 72 65 0a 31 2c 32 30  |fied/ignore.1,20|
00000070  31 32 2d 30 38 2d 30 31  20 28 31 33 3a 33 37 29  |12-08-01 (13:37)|
00000080  2c 30 2e 39 2c 30 2e 39  0a 30 2c 32 30 31 32 2d  |,0.9,0.9.0,2012-|
00000090  30 38 2d 30 33 20 28 31  38 3a 33 37 29 2c 31 2e  |08-03 (18:37),1.|
000000a0  30 2c 31 2e 30 0a                                 |0,1.0.|
000000a6


printf print nooit extra karakters, daarom loop je hier opeens tegenaan.

Helaas is bash trouwens ook zo dat gewoon alle newlines achteraan een file gestripped worden; niet alleen de laatste.

[ Voor 140% gewijzigd door CyBeR op 05-08-2012 22:13 ]

All my posts are provided as-is. They come with NO WARRANTY at all.


Acties:
  • 0 Henk 'm!

  • MisterE
  • Registratie: April 2002
  • Laatst online: 01-10 18:56
ik denk dat je gelijkt hebt.
Als ik dit doe:

blah=$(printf "hoi\n") ; printf "$blah"


dan ben ik ook de newline kwijt. Het zit hem dus ook niet in de "cat" maar waarschijnlijk doet die "=" iets speciaals.

voor mijn gevoel wel raar om een newline achter een bestand te plakken die het al heeft. Aan de andere kant fixt het wel problemen met bestanden die geen newline achter de laatste regel hebben staan :-)

[ Voor 32% gewijzigd door MisterE op 05-08-2012 22:44 ]


Acties:
  • 0 Henk 'm!

  • MisterE
  • Registratie: April 2002
  • Laatst online: 01-10 18:56
ben nog wat in gaan lezen waarom ze dit nu doen.

Het beste voorbeeld is bijv als je "date" intikt, normaal komt hier dan een newline achter (zodat je prompt onder de output komt).
Als je echt het volgende intikt is inderdaad de newline achter de datum weg.
echo The current date is $(date), have a good day!

Ik ben nog over het volgende aan het denken. moet ik nu gewoon achter elke "printf" een newline (\n) gaan zetten? In principe is het alleen nodig voor mijn "wc". Wat is hier de norm voor?

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function getLogStatusCode {  
  local path="${1}/${STATUSFILE}"
  local amount=0; local date=""; local line=""
  
  # scanned before?
  if [ -f "$path" ]; then
    file_lines=$(cat "$path" | grep -v '^#' | grep -v '^$')
    
    # get last session from file
    line=$(printf "$file_lines" | tail -n1)
    
    printf "line is \"$line\""
    
    val=$(printf "$line" | cut -d',' -f1)
    date=$(printf "$line" | cut -d',' -f2)
    engine=$(printf "$line" | cut -d',' -f3)
    script_version=$(printf "$line" | cut -d',' -f4)
    
    # validates the readed line and thus the previous cat
    if [ "$val" = "" -o "$date" = "" -o "$engine" = "" -o "$script_version" = "" ]; then
      printf "CRIT: Config file \"$path\" is corrupt or file permissions are wrong. ABORTING PROGRAM!\n"
      normal_cleanup
      exit $E_ABORTPROGRAM
    fi
    
    #amount=$(cat "$path" | grep -v ^# | grep -v ^$ | wc -l)
    amount=$(printf "$file_lines\n" | wc -l)
    [[ $amount -gt 0 ]] && printf "INFO: Folder is scanned $amount time(s) before\n" && \
    printf "INFO: The last scan was at $date with engine $engine (script version $script_version)\n"
    
    return $val
  else
    return $RV_NEVER_SCANNED
  fi
}

Acties:
  • 0 Henk 'm!

  • Hero of Time
  • Registratie: Oktober 2004
  • Laatst online: 23:03

Hero of Time

Moderator LNX

There is only one Legend

Waarom wil je alles zo specifiek naar printf zetten, ipv gewoon echo houden? Alleen maar omdat het meer POSIX compliant is?

Als je trouwens nadenkt over de newline regel, dan is het toevoegen van een newline niet eens correct. Je hebt een document als dit:
line 1
line 2
line 3

Wat je vervolgens wil gaan maken is dit:
line 1
line 2
line 3


Je maakt dus een lege regel aan het einde. En met 'wc -l' tel je niet de regels, maar hoe vaak \n voorkomt, een newline (of \r, carriage return). Hoe POSIX is dat? Je wilt POSIX compliant zijn door echo te vervangen voor printf, om vervolgens weer niet POSIX te werk te gaan door overal maar een newline achter te plakken.

Commandline FTW | Tweakt met mate


Acties:
  • 0 Henk 'm!

  • Spider.007
  • Registratie: December 2000
  • Niet online

Spider.007

* Tetragrammaton

MisterE schreef op maandag 06 augustus 2012 @ 00:56:
ben nog wat in gaan lezen waarom ze dit nu doen.

Het beste voorbeeld is bijv als je "date" intikt, normaal komt hier dan een newline achter (zodat je prompt onder de output komt).
Als je echt het volgende intikt is inderdaad de newline achter de datum weg.
echo The current date is $(date), have a good day!

[...]
Ik vroeg me ook af waar dit door komt, en het blijkt dat dit niet het aangeroepen script (date) is, maar bash zelf die hierin de output aanpast. Dit is ook als volgt te zien:
echo waa $(date | wc -l) meukee
print "waa 1 meukee", maar inderdaad komt er in de normale output geen newline terug. Eventuele work-arounds hiervoor aan de aanroepende kant zijn hier te vinden

Je hoeft hier dus in je eigen script geen rekening mee te houden. Daarnaast vraag ook ik mij af waarom je printf wilt gebruiken ipv echo :)

---
Prozium - The great nepenthe. Opiate of our masses. Glue of our great society. Salve and salvation, it has delivered us from pathos, from sorrow, the deepest chasms of melancholy and hate

Pagina: 1