19

Ok, something funny happens all of a sudden. This test

for i in `cat /mnt/usb/liste.txt `; do [ -f /mnt/usb/lsdvd.xml/$i ] || echo $i; done

used to work fine (for every entry in the file liste.txt try to find a corresponding directory, print the name if not found) and used to yield the names of directories missing. Now this command yields

 echo: command not found
 echo: command not found
 echo: command not found
(...)

I've tried using [[...]] and "test" instead of "[ ..]" but to no avail.

Any ideas what might have happened with my beloved bash while I wasn't looking :) ?

Thanks, Christian.

Edit (set -x output):

(...)
+ for i in '`cat /mnt/usb/liste.txt`'
+ '[' -f /mnt/usb/lsdvd.xml/THE_GHOST_WRITER.lsdvd.xml ']'
+ for i in '`cat /mnt/usb/liste.txt`'
+ '[' -f /mnt/usb/lsdvd.xml/THE_IMAGINARIUM_OF_DOCTOR_PARNASSUS.lsdvd.xml ']'
+ for i in '`cat /mnt/usb/liste.txt`'
+ '[' -f /mnt/usb/lsdvd.xml/THE_INFORMANT.lsdvd.xml ']'
+ for i in '`cat /mnt/usb/liste.txt`'
+ '[' -f /mnt/usb/lsdvd.xml/THE_INTERNATIONAL.lsdvd.xml ']'
+ for i in '`cat /mnt/usb/liste.txt`'
+ '[' -f /mnt/usb/lsdvd.xml/THE_MEN_WHO_STARE_AT_GOATS.lsdvd.xml ']'
+ for i in '`cat /mnt/usb/liste.txt`'
+ '[' -f /mnt/usb/lsdvd.xml/THE_OTHER_MAN.lsdvd.xml ']'
+ for i in '`cat /mnt/usb/liste.txt`'
+ '[' -f /mnt/usb/lsdvd.xml/THE_QUEEN.lsdvd.xml ']'
+ for i in '`cat /mnt/usb/liste.txt`'
+ '[' -f /mnt/usb/lsdvd.xml/THE_READER.lsdvd.xml ']'
+ for i in '`cat /mnt/usb/liste.txt`'
+ '[' -f /mnt/usb/lsdvd.xml/THE_REBOUND.lsdvd.xml ']'
+ $'\302\240echo' THE_REBOUND
+ '[' -x /usr/lib/command-not-found ']'
+ /usr/bin/python /usr/lib/command-not-found -- $'\302\240echo'
 echo: command not found
+ return 127
(...)
Christian
  • 191
  • 1
  • 1
  • 4
  • have you try to double-quote `$i` ? – Yannick Loiseau Mar 21 '11 at 17:47
  • If you replace the end of the line with `echooooo $1; done`, does it give an error `echooooo: command not found`? That "command not found" error is what I get when I type junk at a bash command prompt. What if you replace it with `/bin/echo`? – David Yaw Mar 21 '11 at 17:56
  • 1
    Add `set -x` to the top of your script and watch each command that the shell executes. – bobbogo Mar 21 '11 at 18:17
  • My findings: Double quoting $i: no avail, same error.  echoooo: command not found. – Christian Mar 22 '11 at 09:48

4 Answers4

38

If you look closely, you will see it's printing:

 echo: command not found

with a leading space, rather than:

echo: command not found

set -x makes this much clearer when it prints:

$'\302\240echo' THE_REBOUND

0302 0240 is octal UTF-8 for a non-breaking space.

Try deleting the space between | and echo and type a normal space.


Chances are, the file was edited on a Mac, where a non-breaking space can be entered accidentally if you press Option at the same time as Space.

If you're using Vim, you can make non-breaking spaces more obvious by using the listchars option. For example:

set listchars+=nbsp:% list

See Making Vim highlight suspicious characters for some more ideas.

On Linux, non-breaking space is either Compose Space Space or Ctrl+Shift+ua0, so you're probably not going to type that by accident.


For anyone interested, it's possible to manually convert the octal bytes to UTF-8 using the UTF-8 table from the UTF-8 Wikipedia article.

But by far the easiest way I found was using Python:

>>> import unicodedata
>>> unicodedata.name('\302\240'.decode('utf-8'))
'NO-BREAK SPACE'
Mikel
  • 24,855
  • 8
  • 65
  • 66
3

Edit: The code below is still fine, but the issue is probably in $'\302\240echo': There seems to be unknown characters in your text file. Try removing the couple characters before echo and then typing them again.

It could well be a quoting issue. Also, you could save some time by avoiding the useless use of cat:

while IFS= read -r; do [ -f "/mnt/usb/lsdvd.xml/$REPLY" ] || echo "$REPLY"; done < /mnt/usb/liste.txt
l0b0
  • 55,365
  • 30
  • 138
  • 223
2

What happens when you run simply:

for i in `cat /mnt/usb/liste.txt `; do
    echo $i
done

For one thing, do you notice anything abnormal about the filenames (spaces, newlines, special characters, etc)? If so, you will need to quote the filename to keep the shell from mis-interpreting it.

Also, try using a normal if statement instead of the logical OR:

for i in `cat /mnt/usb/liste.txt `; do
    if [ ! -f /mnt/usb/lsdvd.xml/$i ]; then
        echo $i
    fi
done
bta
  • 43,959
  • 6
  • 69
  • 99
  • The simple for-echo-done loop works fine, nothing unusual about the filenames. Actually, the are quite nice: no spaces, not even numbers. – Christian Mar 22 '11 at 09:54
  • The for-if-then-fi-done loop works fine, so it must be something about the || and strange unquoted strings, but I can't seem to find anything unusual about the files and their names. – Christian Mar 22 '11 at 09:55
0

Works for me:

for f in $(< d2.lst); do [ -f ./d2/$f ] || echo $f ; done

Just my own filenames, directories, and suggested construct $(...) instead of backticks, and with < instead of cat.

Maybe a dos/windows linefeed in your list? View it with less.

user unknown
  • 35,537
  • 11
  • 75
  • 121