Vraag Verwarring met het gebruik van grep met *?


Ik was onlangs in gesprek met een collega terwijl hij in zijn schulp zat, toen ik hem iets zag doen ls -l | grep asdf*.

"Waarom de glob?" Ik vroeg hem. "Het is gewoon de manier waarop ik het altijd doe," antwoordde hij.

Ik heb niet meteen problemen gezien, maar het voelde nog steeds verkeerd. Toen ik het later zelf probeerde, zag ik ander gedrag:

--> ls -l | grep ls
-rwxr-xr-x 1 root root   22896 Nov 19  2012 false
-rwxr-xr-x 1 root root  105840 Nov 19  2012 ls
-rwxr-xr-x 1 root root   44640 Nov 19  2012 lsblk
-rwxr-xr-x 1 root root    6272 Nov 19  2012 lsmod
-rwxr-xr-x 1 root root   31912 Nov 19  2012 ntfsls

--> ls -l | grep ls*
Binary file lsblk matches
Binary file lsmod matches

Wat gebeurt hier in vredesnaam? In het ergste geval dacht ik dat grep het zou behandelen als de regex l(s*) en geef me elk voorkomen van l, maar deze invoer verschijnt niet eens in het ls! (Ik voer dit uit /bin).

Wat doet grep als u een glob achter uw zoekreeks plaatst? Moet ik mijn collega vertellen dit in de toekomst niet meer te doen?


1
2017-08-07 16:53


oorsprong




antwoorden:


Wanneer je dat doet grep ls*, de schelp breidt zich eerst uit ls* naar een lijst met overeenkomende bestanden in de huidige map, zodat het commando wordt

ls -l | grep ls lsblk lsmod

In dit geval, grep negeert de standaardinvoer en behandelt het eerste argument ls als een patroon dat moet worden vergeleken binnen de bestanden lsblk en lsmod, net alsof je hebt getypt grep ls lsblk lsmod (vermoedelijk in /bin):

$ grep ls lsblk lsmod
Binary file lsblk matches
Binary file lsmod matches

Aan de andere kant, als er geen glob-overeenkomsten in de huidige map en de shell's zijn nullglob optie is niet ingesteld ls* zal overblijven unuitgebreid, dus dat grep ziet ls* en komt overeen met elk bestand namen bij elkaar passen l gevolgd door nul of meer s tekens (eigenlijk elke bestandsnaam met een l erin) bijvoorbeeld:

$ pwd
/home/steeldriver
$ echo ls*
ls*

(er zijn geen bestanden die overeenkomen met de shell glob ls* in mijn thuismap); dan

$ ls /bin | grep 'ls*'
bzless
chacl
false
.
.
.
zless

tl; dr doe dat niet


4
2017-08-07 16:59



Doet grep negeer dan stdin? Er wordt niet eens aandacht besteed aan wat er in het spel was? Ook als ik loop ls -l /bin | grep ls* het resultaat ziet eruit alsof het overeenkomende regex is l(s*), is daar een verklaring voor? - scohe001
@ scohe001 Ja, ik geloof dat dat het geval is: als man grep zegt: "Als er geen bestanden zijn opgegeven of als het bestand" - "wordt gegeven, zoekt grep naar standaardinvoer.". In het tweede geval, tenzij je shell's nullglob is ingesteld, dan als er geen overeenkomende bestanden in uw huidige map staan, dan gaat de schelp weg ls*  unuitgebreid, welke grep zal dan behandelen als een regex-vergelijking l gevolgd door nul of meer ss. - steeldriver


Om veiliger te zijn, moet uw collega het volgende gebruiken:

ls -l | grep "asdf*"

om de uitvoer met piping te verwerken, gebruiken we citaten die we overslaan met shell-bestanden, dus we zeggen dat er naar lijnen gezocht wordt asd gevolgd door nul of meer f, een beter gebruik is:

ls -l | grep "asdf.*"

Het andere ding om te vermelden is dat als er geen enkel bestand in de huidige map was dat overeenkwam met het patroon, het zal worden beschouwd zoals het is door grepMeestal is dat wat er gebeurt.

Merk ook op dat het ontleden is ls uitvoer is geen goede zaak om te doen.


3
2017-08-07 17:03