Bash – Code works manually on terminal but can’t run script

bashshell-script

I created this script to backup my postgresql database with cron:

backup.sh

#!/bin/bash
export PGUSER="user"
export PGPASSWORD="pass"
FECHA_ACTUAL=`date +%Y-%m-%d`
HORA_ACTUAL=`date +%H:%M`
ARCH_RESP=$FECHA_ACTUAL-$HORA_ACTUAL
pg_dump -O -Fc mydb -h localhost > /home/user/backups/backup_$ARCH_RESP.sql
find /home/user/backups/ -name '*.sql' -mtime +2 -exec rm -f {} \;
unset PGUSER
unset PGPASSWORD

If I copy and paste this code on the terminal it works fine, but if I try to run the script, I get this error:

user@dental:~/scripts$ ./backup.sh
export: bad interpreter: no such file or directory

Is there something wrong with my script? Or is it the wrong interpreter as it says?

Best Answer

I can get the same error if the first line is terminated only with a CR (instead of LF):

$ echo -en '#!/bin/bash\rexport foo=bar\n' > test.sh
$ chmod +x test.sh
$ ./test.sh
export: bad interpreter: No such file or directory

What happens is that the kernel looks for an interpreter program called /bin/bash\rexport, doesn't find it, and drops an error. Bash prints an error message with the name of the file

bash: ./test.sh: /bin/bash\rexport: bad interpreter: No such file or directory

but since the carriage return moves the output back to the front of the line, you see only

export: bad interpreter: No such file or directory

So the problem seems to be with the line endings.

Note that with a DOS-style CRLF line ending, the result is different, since there is an LF to end the line now.

$ echo -en '#!/bin/bash\r\nexport foo=bar\n' > test.sh
$ ./test.sh    
bash: ./test.sh: /bin/bash^M: bad interpreter: No such file or directory

Though I don't know why bash seems to quote the CR on output as ^M this time.


IIRC the lone CR as a line ending is a remnant of old Mac systems, and dos2unix doesn't seem to fix it by default. You'd need to use mac2unix or dos2unix -c mac.

Something like this should also turn all of CR or CRLF to Unix-style LF line endings, if you happen to have all styles mixed up and have no need for the CR's in any other sense.

sed 's/\r/\n/g;s/\n$//' backup.sh
Related Question