8

When I login, I have these messages:

-bash: $'\r' : command not found
-bash: $'\r' : command not found
-bash: $'\r' : command not found 

It is quite clear that it is caused by Windows-style line endings in some startup script(s), so my question is: Can I track script that causes that and how?

  • 2
    Try looking at the .bashrc,.bash_profile and profile files in your home directory as well as /etc/profile – Raman Sailopal Mar 15 at 13:03
14

Bash reads a number of different files on startup, even depending on how it's started (see the manual for the description). Then there's stuff like /etc/profile.d/ that aren't directly read by the shell, but can be referenced from the other startup files in many distributions.

You'll have to go through all of those but luckily, you can just grep for the carriage return. Try e.g. something like:

grep $'\r' ~/.bashrc ~/.profile ~/.bash_login ~/.bash_profile /etc/bash.bashrc /etc/profile /etc/profile.d/*

See also Is it possible to find out which files are setting/adding to environment variables, and their order of precedence? for a similar issue.

5

file(1) can be helpful here as well.

$file *

signin:                                     Python script, ASCII text
signup:                                     Python script, ASCII text, with CRLF line terminators
site_off.htm:                               XML 1.0 document, ASCII text
sitemaps:                                   directory

I can see that signup needs to have those pesky Windows CRLF line-endings removed.

For a recursive directly like /home/username you could probably combine with find and xargs (and maybe a grep, too):

$ find . | xargs file | grep CR

./foo_data/V: ASCII text, with CR, LF line terminators
./foo_data/Y: ASCII text, with CR, LF line terminators
3

Another method is to take all of those startup scripts mentioned, and echo a string identifying each one at the start of each one.

$ head .bashrc
echo "Running bashrc"

Then, on login, you will see something like this:

running bashrc
running bash_aliases
-bash: $'\r' : command not found
-bash: $'\r' : command not found
-bash: $'\r' : command not found 
running something_else

At that point you can conclude that, (in the example above) .bash_aliases contains the offending line endings.

Once you have identified the file, but the problem lines don't jump out at you, you can use the same method to track down the line. Echo a message halfway through the file, then 3/4ths or 1/4s through, depending on the output. That way you can track down the line, depending on whether it echoes before or after your echo.

  • Yeah, this method is good if one can quickly automize it, otherwise it is almost the same as look through all these files. – Denis Sablukov Mar 15 at 20:16
  • 1
    Note that you might want to also say 'done running <file>' at the end of each one. In this case it doesn't really matter unless only some of the lines have CR line endings, but if you're looking for another error it could be in your .bashrc after you source .bash_aliases. – Ben Millwood Mar 16 at 0:19
  • 1
    For someone just learning to debug shell issues, or when it is not as easy as searching for '\r', THIS answer is worth having in your knowledge toolbox. I inherited a complex build system which was a rat's nest of entwined scripts to do remote builds over SSH. This was the only way to unwind it and move it to Docker containers. – Scott Prive Mar 16 at 14:47
  • Another general tip - when dealing with inter-related Bash scripts, be mindful of where you add echo statements and (whatever it is you're doing) test frequently. If a bash script is used to output strings to STDOUT and you added debug statements to STDOUT then you probably broke the thing you were debugging. Sometimes the answer is to employ the "logger" command to add info/debug to a script. Other times use STDERR, if it's a warning condition. – Scott Prive Mar 16 at 14:50
  • @DenisSablukov if your files are long, and looking through them takes a while, this method will help you narrow down the source more quickly. It doesn't take very long to at a line to the top and bottom of 6 files. – user394 Mar 16 at 15:12
3

I take the hard part of this question to be not "hwo can I find carriage returns in a file?" but "how can I find out which files my bashrc uses?"

For the second question, you can try something like this:

bash -x .bashrc

This will show you everything your bashrc does, including all the files it refers to. It's noisy, but should help you track down which files are being used.

Except in fact, my (and many other) .bashrc files exit early if not run interactively, so you have to trick it into passing that check:

bash -ix .bashrc

Here the -i forces interactive mode.

To grep out just the cases where you source a file, something like this works for me but I can't promise the regex catches everything:

bash -ix .bashrc 2> >(grep -E '^\+* (\.|source)')

I guess you might also want the error messages, so something like:

bash -ix .bashrc 2> >(grep -E -e '^\+* (\.|source)' -e 'command not found')

If for some reason none of this worked, I would resort to strace -e open bash or something like that, to find every time any file is opened by your bash session. But that's an even more heavyweight / noisy solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.