Fix Windows Line Endings and Make Shell Scripts Executable in Linux
If you edit Linux shell scripts on Windows, you may run into confusing errors when you copy those scripts back to Ubuntu or another Linux server.
The script may look correct, but Linux can still fail to run it because Windows and Linux use different line endings. Windows commonly saves text files with CRLF line endings. Linux shell scripts should use LF line endings.
At the same time, copied scripts may not have execute permission. That means the file exists, but Linux will not run it as a program until you add chmod +x.
This article shows the common errors and a single command that fixes both problems for every .sh file in the current folder tree.
Common Errors
One common error is:
/bin/bash^M: bad interpreter: No such file or directory
The ^M means the file has Windows carriage-return characters at the end of each line.
You may also see:
bash: ./deploy.sh: Permission denied
That usually means the script does not have execute permission.
Another possible error is:
./deploy.sh: line 2: $'\r': command not found
This also points to Windows line endings inside the script.
Why This Happens
Linux and Windows store line breaks differently:
- Linux uses
LF. - Windows often uses
CRLF.
The extra Windows carriage-return character is invisible in many editors, but Bash can still read it. When Bash sees that hidden character in places like the shebang line, commands, or variable assignments, the script can fail.
For example, this first line may look normal:
#!/bin/bash
But if the file has Windows line endings, Linux may read it like:
#!/bin/bash^M
Linux then tries to find an interpreter named /bin/bash^M, which does not exist.
Check the Script
Move into the folder that contains your scripts:
cd /srv/admin/scripts
List the shell scripts:
find . -type f -name "*.sh" -print
Example output:
./deploy-site.sh ./inventory/check-server.sh ./maintenance/backup-database.sh
If one of these files was edited on Windows, it may need its line endings fixed.
Fix Line Endings and Make Scripts Executable
Run this command from the folder where you want to repair shell scripts:
find . -type f -name "*.sh" -print -exec sed -i 's/\r$//' {} \; -exec chmod +x {} \;
What the command does:
find .starts in the current folder.-type fonly matches files.-name "*.sh"only matches shell scripts ending in.sh.-printshows each file that is being changed.sed -i 's/\r$//'removes Windows carriage-return characters from the end of each line.chmod +xmakes each script executable.
Example output:
./deploy-site.sh ./inventory/check-server.sh ./maintenance/backup-database.sh
After this runs, each .sh file should have Linux line endings and execute permission.
Test a Script
Run one of the scripts again:
./deploy-site.sh
If you still get a permission error, check the permissions:
ls -l deploy-site.sh
You should see x in the permissions, like this:
-rwxrwxr-x 1 admin admin 2401 Jul 2 22:18 deploy-site.sh
The x means the file is executable.
Run the Fix Safely
Be careful where you run the command. It works recursively from the current folder downward.
Before changing files, you can preview which .sh files will be touched:
find . -type f -name "*.sh" -print
If the list looks correct, run the full fix:
find . -type f -name "*.sh" -print -exec sed -i 's/\r$//' {} \; -exec chmod +x {} \;
If you only want to fix one folder, change into that folder first:
cd /srv/admin/scripts/site-maintenance
find . -type f -name "*.sh" -print -exec sed -i 's/\r$//' {} \; -exec chmod +x {} \;
Fix One Script Only
If you want to fix a single file instead of every .sh file, run:
sed -i 's/\r$//' deploy-site.sh chmod +x deploy-site.sh
Then run it:
./deploy-site.sh
Prevent the Problem
Many editors can save files with Linux line endings.
In Visual Studio Code, check the lower-right corner of the window. If it says CRLF, click it and change it to LF, then save the file.
If your team stores scripts in Git, you can also use a .gitattributes file to keep shell scripts as Linux-style text:
*.sh text eol=lf
That helps prevent Windows edits from reintroducing CRLF line endings into shell scripts.
Quick Reference
Preview affected scripts:
find . -type f -name "*.sh" -print
Fix all .sh files below the current folder and make them executable:
find . -type f -name "*.sh" -print -exec sed -i 's/\r$//' {} \; -exec chmod +x {} \;
Fix one script:
sed -i 's/\r$//' deploy-site.sh chmod +x deploy-site.sh
This is a simple cleanup step, but it fixes two of the most common problems with shell scripts that were edited on Windows: hidden CRLF characters and missing execute permission.