als verklaring regex of slechte echo? (bash 3.0)

Kan iemand me vertellen waarom dit gebeurt? Ik probeer wat regels in te voegen voor een exemplaar van een gegeven string, zeg ...

thing
extern void hello_dude(char *loc, long length){
thing

naar

thing
another
extern void hello_dude(char *loc, long length){
thing

with a simple (sigh) bash 3.0 script, the thing is that the if statement im using naar match the string is echoing the line splitted like this:

thing
another
extern
void
hello_dude(char
*loc,
long
length){
thing

de verklaring is

elif [[ "$LINE" =~ *hello_dude\(* ]]; then
    echo "$LINE" >> temp2

er is duidelijk een leidende if-verklaring die OK werkt voor het elif.

Ive probeerde elke citaataroma en regex die ik me kan voorstellen ...

alle hulp wordt zeer op prijs gesteld

EDIT: dit is het daadwerkelijke script dat ik gebruik

#!/bin/bash

for LINE in `(cat temp1)`
do
  if [[ "$LINE" = sendMessage4K* ]]; then
     echo '/*---RUAISI---*/' >> temp2
     echo "$LINE" >> temp2
   elif [[ "$LINE" =~ *alpha_display\(* ]]; then
     echo "$LINE" >> temp2
     echo '/*---RUAISI---*/' >> temp2
  else
     echo "$LINE" >> temp2
  fi
done

het bestand temp1 is:

FIX
sendMessage4K(NomRPC,sbuffer,"KP07");
FIX
extern void alpha_display(char *loc, long length){
  FIX
}
FIX

the idea is naar get temp2 with:

FIX
/*---RUAISI---*/
sendMessage4K(NomRPC,sbuffer,"KP07");
FIX
extern void alpha_display(char *loc, long length){
/*---RUAISI---*/
  FIX
}
FIX

maar ik krijg dit

FIX
/*---RUAISI---*/
sendMessage4K(NomRPC,sbuffer,"KP07");
FIX
extern
void
alpha_display(char
/*---RUAISI---*/
*loc,
long
length){
FIX
}
FIX
0
@larsks: ive bewerkte de Q met het eigenlijke bestand en script dat ik gebruikte.
toegevoegd de auteur noobroot, de bron
nu ben ik vrij zeker dat het iets te maken heeft met $ LINE met spaties (spaties) erin ...
toegevoegd de auteur noobroot, de bron
Kun je ons het script laten zien? Omdat we bijvoorbeeld niet weten hoe $ LINE eruit ziet.
toegevoegd de auteur larsks, de bron
heb je de IFS ingesteld op iets dat niet de standaardwaarde is? Succes.
toegevoegd de auteur shellter, de bron
beter om bovenstaande opmerking over IFS = z te verwijderen om nieuwe lezers niet te verwarren. ;-) succes.
toegevoegd de auteur shellter, de bron

3 antwoord

Zonder je script te zien, kunnen we je daar niet echt mee helpen. Dit soort problemen - het invoegen van een regel tekst vóór een bepaald overeenkomend patroon - wordt echter vaak afgehandeld met behulp van sed . Als ik bijvoorbeeld een bestand heb dat er zo uitziet:

one
two
three

En ik wil "Bananen" vóór "twee" invoegen, ik zou zoiets als dit doen:

sed '/ two/i \ Bananas'

Dat geeft mij:

one
Bananas
two
three

Dit veronderstelt GNU sed (hoewel het zou werken met kleine wijzigingen voor andere versies van sed, ook).

1
toegevoegd

EDIT: Whoops, my answer mostly duplicates the one from choroba. I'm going to leave it here because I think it goes into a little more detail about the why of things, but you should probably accept choroba's.

Uw probleem is hier:

for LINE in `(cat temp1)`

Hiermee wordt elke regel opgesplitst, zodat een invoerregel als deze wordt weergegeven:

extern void alpha_display

Je krijgt een for-lus die er ongeveer zo uitziet:

for LINE in extern void alpha_display; do

Wat betekent dat LINE is ingesteld op, in de volgende volgorde:

  1. extern
  2. ongeldig
  3. alpha_display

Om dit aan te tonen, probeer het volgende kleine script:

for LINE in `cat temp1`; do
  echo "$LINE"
done

Als u een bestand regel voor regel wilt lezen, kunt u beter lezen gebruiken in een while lus met invoer omgeleid vanuit uw souce-bestand. Vergelijk de uitvoer van het volgende met wat het vorige script produceert:

while read LINE; do
  echo "$LINE"
done < temp1

Met dit in gedachten kun je je script als volgt repareren:

while read LINE; do
  if [[ "$LINE" = sendMessage4K* ]]; then
     echo '/*---RUAISI---*/' >> temp2
   elif [[ "$LINE" = *alpha_display\(* ]]; then
     echo '/*---RUAISI---*/' >> temp2
   fi

   echo "$LINE" >> temp2
done < temp1

Merk op dat naast het gebruik van een while lus, ik ook de operator voor de reguliere expressie heb verwijderd uit de expressie elif (omdat, zoals eerder is opgemerkt, u gebruikt glob-expressies in plaats van reguliere expressies), en ik heb een aantal redundante code geëlimineerd.

Dit script produceert de volgende uitvoer:

FIX
/*---RUAISI---*/
sendMessage4K(NomRPC,sbuffer,"KP07");
FIX
extern void alpha_display(char *loc, long length){
/*---RUAISI---*/
FIX
}
FIX

Omdat lezen feitelijk nog steeds dingen splitst op IFS (en ze vervolgens weer samenvoegt), verliest u uiteindelijk voorlopende of achterliggende witruimte. U kunt dit oplossen door IFS alleen end-of-line te laten opnemen door het volgende toe te voegen aan de bovenkant van het script:

IFS='\n'

Ik zou nog steeds willen voorstellen dat bash niet noodzakelijk het juiste hulpmiddel is voor deze taak. Of sed of awk zal waarschijnlijk effectiever zijn. Hier is hetzelfde als een awk-script:

#!/usr/bin/awk

/sendMessage4K/ || /alpha_display\(/ {
    print "/*---RUAISI---*/"
    print
    next
}

{print}

Als je dit in een bestand met de naam "fixit.awk" hebt opgeslagen, zou je het als volgt moeten uitvoeren:

awk -f fixit.awk < temp1 > temp2
1
toegevoegd
heel erg bedankt voor zo'n uitgebreid antwoord, ik heb eigenlijk iets geleerd ... zoals je zei sinds het antwoord van choroba de 1e was die ik voel dat ik gedwongen ben het te accepteren. Ik waardeer het echt joh
toegevoegd de auteur noobroot, de bron
niet genoeg rep ik bang zijn ...
toegevoegd de auteur noobroot, de bron
... wat natuurlijk niet verhindert dat u deze stemt :);
toegevoegd de auteur larsks, de bron

U gebruikt de operatof voof reguliere expressie die overeenkomt met ~, maar aan de rechterkant van de regel is er geen reguliere expressie, maar een shell-jokertekenuitdrukking. Dus verander het naar

[[ $LINE == *hello_dude\(* ]]

of

[[ $LINE =~ hello_dude\( ]]

i.e. use either wildcard with the proper operatof, of a regex with the proper operatof.

Update: Looking at the updated script, I see the problem: you are using fof where you should be using while:

#! /bin/bash

while read LINE ; do
  if [[ $LINE = sendMessage4K* ]]; then
     echo '/*---RUAISI---*/' >> temp2
     echo "$LINE" >> temp2
   elif [[ $LINE =~ *alpha_display\(* ]]; then
     echo "$LINE" >> temp2
     echo '/*---RUAISI---*/' >> temp2
  else
     echo "$LINE" >> temp2
  fi
done < temp1

To avoid deletion of leading whitespace, add this line befofe the while:

IFS=$'\n'
1
toegevoegd
Ik heb allebei geprobeerd zonder geluk ... dezelfde resultaten toch bedankt
toegevoegd de auteur noobroot, de bron
@shellter: de IFS = z was een test gebaseerd op totale duisternis met betrekking tot het gebruik van de IFS-waarde, nu weet ik het, thx
toegevoegd de auteur noobroot, de bron
@choroba: Heel erg bedankt man, nu werkt het, het was de IFS-waarde die de schuldige was, zou je vriendelijk genoeg zijn om mijn reeds verslagen neuron uit te leggen, wat is het verschil tussen terwijl en voor in deze escenario? ... nevermind i commentaar geleverd voordat het antwoord van de larsks werd gelezen
toegevoegd de auteur noobroot, de bron
@noobroot: per mijn opmerking hierboven ziet horoba's idee voor IFS = $ '\ n' er goed uit (je hebt IFS = z waarom ?!). Nu moet je een printf "ZZZ $ {LINE} ZZZ \ n" toevoegen net na de while om precies te zien wat er in elke regel staat, en hoe het overeenkomt met de reg-ex. Is uw originele bestand gemaakt door een op Windows gebaseerde applicatie en draait u dit nu onder Linux? Als dat zo is, dan moet je dos2unix myProblemFile.txt ;-) Veel geluk gebruiken.
toegevoegd de auteur shellter, de bron
@noobroot: probeer het choroba-script hierboven aan te passen, zodat alle verwijzingen binnen [[....]] naar $ LINE nu "$ LINE" zijn (of tenminste de eerste). Succes.
toegevoegd de auteur shellter, de bron