Languages and Scripting

Re: need to do "od -x" on filenames

 
Allanm
Super Advisor

need to do "od -x" on files


I am trying to look for Control M characters in files on a particular directory and subdirectories underneath:

find . -type f -print |xargs od -x |grep 0d

All i get from this is a bunch of hexa numbers and not the actual filenames that have the od character.

Another way I tried was this:

for i in `find . -type f`; do echo $i; od -x $i |grep 0d ; done

but still get a very long list of ongoing hexa numbers...

I just want to know which files have the control M ^M character and should not display hexa numbers.

Any help would be greatly appreciated.

Thanks,
Allan.
7 REPLIES 7
Matti_Kurkela
Honored Contributor

Re: need to do "od -x" on files

In this case, the computer does exactly what you say, instead of what you mean.

In your command lines, there is no way for the grep to know anything about the filenames, as there are no filenames in the output of the od command.

The grep command has the option "-l" (list filenames only) which would be ideal to your problem. So it would be advantageous to skip the "od" and let grep do all the work. However, telling grep to recognize the ^M character is a bit tricky.

Off the top of my head, I'd do it this way:

find . -type f -exec grep -l $(echo '\r\c') {} \+

NOTE the plus sign at the end: the "-exec [...] {} \+" construct is functionally the same as "-print | xargs [...]", but unlike xargs, it is immune to spaces and other difficult characters in the filenames.

MK
MK
Allanm
Super Advisor

Re: need to do "od -x" on files


Thanks for replying so quickly MK,

When I ran your command it gave me the following error:

find . -type f -exec grep -l $(echo '\r\c') {} \+

find: missing argument to `-exec'

Also my xargs doesnt seem to work witg "grep -l" since the way I am using it :

find . -type f |xargs od -x |grep -l 0d
(standard input)
xargs: od: terminated by signal 13

Please suggest where I am going wrong.
Hein van den Heuvel
Honored Contributor

Re: need to do "od -x" on files

You are thinking too complex.
Just grep for ^M, which is a "carriage Return" and expressed as "\r"
(compare with "\n" for New-line)

So I think you just want a simple:

find . -type f | grep -e "\r" | od -c

Note, this will not cause false positives on the text "\r" in the file name, this is just the represenation of 1 control character.

Now you do not just want to print the filename, because that very ^M will cause the initial part to be overwritten.

Try this as well:

$ find . -type f | perl -ne 'print if s/\r/ /'

Finally... count yourself lucky you did not have to hunt for file names with new-lines!
You would then have to search non-line based for "\n" NOT followed by ./ nor EOF.

hth,
Hein.
James R. Ferguson
Acclaimed Contributor

Re: need to do "od -x" on files

Hi:

You can always list non-printing characters in the filenames in octal '\ddd\' notation by doing:

# ls -b

Regards!

...JRF...
Hein van den Heuvel
Honored Contributor

Re: need to do "od -x" on files

Thanks JRF! I alwasy forget about the -b option.

The simple solution then becomes:

$ ls -bR | grep -h \015
test\015with carriage return
$

Using find is a little trickier.
I got an echo on the output which I can not immediatly explain/supress.

$ find . -exec ls -b {} \; | grep -h \015
test\015with carriage return
./tmp/test\015with carriage return

Cheers,
Hein.


Dennis Handly
Acclaimed Contributor

Re: need to do "od -x" on filenames

>not the actual filenames that have the 0d character.

It would have been helpful if you said filename and didn't imply file contents in your subject.

>All I get from this is a bunch of hex numbers and not the actual filenames that have the 0x0d character.

Besides the correct solution Of JRF's with ls -b, you can use different tools:
1) Use GNU grep with context:
find . -type f | xd -tx1 -tc | grep -B1 0d

2) Use sed to combine pairs of lines:
find . -type f | xd -tx1 -tc | sed -n -e 'N; /0b/p'

3) Find the name directly:
find . -type f -name "*control-VcontrolM"
Note you may have to put this in a script. In my real shell I can't do this. You might be able to do this with MK's suggestion:
"$(echo '*\r*\c')"

4) Use vis(1):
find . -type f | vis | grep '\r'

>find . -type f | xargs od -x | grep 0d

This looks at the file contents.

>for i in `find . -type f`; do echo $i; od -x $i |grep 0d ; done

This looks at the name. To get the name vs hex you could do:

find . -type f | while read name; do
    echo $name | xd -x | grep -q 0d
    if [ $? -eq 0 ]; then
       echo $name
    fi
done

>MK: find . -type f -exec grep -l $(echo '\r\c') {} \+

You probably need to quote the echo to solve the missing argument:
"$(echo '\r\c')"

>Also my xargs doesn't seem to work ...

We don't want you to use your xargs, since it looks inside the files.

>Hein: Just grep for ^M, which is a "carriage Return" and expressed as "\r"

A real shell doesn't understand \r, only echo and inv(1).

>you do not just want to print the filename, because that very ^M will cause the initial part to be overwritten.

Put it in a file and you can see both parts with vi.

>$ ls -bR | grep -h \015

You need to quote that "\": ... | grep '\015'

>I got an echo on the output which I can not immediately explain/suppress.

Where?

>$ find . -exec ls -b {} \; | grep -h \015

Try:
$ find . -exec ls -b {} + | grep '\015'

Dennis Handly
Acclaimed Contributor

Re: need to do "od -x" on filenames

>You need to quote that "\": ... | grep '\015'

Oops, you need to do: ... | grep '\\015'

>>I got an echo on the output which I can not immediately explain/suppress.

Ah, you need to use ls -db
$ find . -exec ls -db {} + | grep '\\015'