grep1-2 Exercise 3: Passwords, Hidden Files and a Name with Spaces =================================================================== (Run from an empty folder. The first block builds the practice project from the chapter; your own tree can skip it.) mkdir -p project/src project/notes project/build project/logs project/data project/.git "project/my notes" cd project printf '# Demo project\nTODO write the install guide\nRun app.py to start\n' > README.md printf 'import os\n# TODO handle errors\ndef main():\n print("hello")\n' > app.py printf 'def helper():\n # TODO remove this\n return 1\n' > src/util.py printf '// TODO rename\nconsole.log("hi");\n' > src/main.js printf 'buy milk\nTODO call the plumber\n' > notes/todo.txt printf '/* generated */ var a = 1; // TODO generated noise\n' > build/bundle.js printf 'INFO started\nERROR something broke\n' > logs/app.log printf 'data\0TODO inside a binary file\n' > data/image.bin printf 'API_KEY=abc123\npassword=hunter2\n' > .env printf '[core]\n\trepositoryformatversion = 0\n# TODO placeholder inside .git\n' > .git/config printf 'TODO book the room\npassword reminder: change it\n' > "my notes/meeting notes.txt" # --- the exercise --- echo "--- by listing with a star: misses hidden files" grep -rl password * echo "--- walking the folder: finds .env too" grep -rl password . echo "--- the version that breaks on a space:" grep -rl password . | xargs wc -l echo "--- the safe version:" grep -rlZ password . | xargs -0 wc -l Output: --- by listing with a star: misses hidden files my notes/meeting notes.txt --- walking the folder: finds .env too ./.env ./my notes/meeting notes.txt --- the version that breaks on a space: 2 ./.env wc: ./my: No such file or directory wc: notes/meeting: No such file or directory wc: notes.txt: No such file or directory 2 total --- the safe version: 2 ./.env 2 ./my notes/meeting notes.txt 4 total WHY THIS WORKS AS AN ANSWER --------------------------- The star version misses .env because the shell never passes names that start with a dot. The dot version lets grep walk the folder itself. In the broken version xargs splits './my notes/meeting notes.txt' at the spaces, so wc is asked about './my', 'notes/meeting' and 'notes.txt', none of which exist, and it reports an error for each while still counting the file it could read. In the safe version -Z ends each name with a zero byte and xargs -0 splits on that, so the name arrives as one argument. The total line is wc's own.