shell 脚本对编码和行结尾敏感吗?

发布于 2025-01-20 00:37:47 字数 1569 浏览 5 评论 0 原文

我正在MacOS上制作NW.JS应用,并希望以Dev模式运行该应用程序 通过双击图标。 在第一步中,我正在尝试使我的shell脚本起作用。

在Windows上使用VS代码(我想获得时间),我在项目的根部创建了一个 run-nw 文件,其中包含

#!/bin/bash

cd "src"
npm install

cd ..
./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &

内容

$ sh ./run-nw

: command not found  
: No such file or directory  
: command not found  
: No such file or directory  

Usage: npm <command>

where <command> is one of:  (snip commands list)

(snip npm help)

[email protected] /usr/local/lib/node_modules/npm  
: command not found  
: No such file or directory  
: command not found

以下 理解。

  • 看来它作为命令为空行。 在我的编辑器(VS代码)中,我尝试用 \ r \ n \ n 替换 (如果 \ r 会产生问题),但没有任何改变。
  • 看来它找不到文件夹 (有或没有 dirname 指令), 也许它不知道 cd 命令?
  • 看来它不了解安装参数到 npm
  • 真正奇怪我的部分是它仍然运行该应用程序 (如果我手动进行 npm安装)...

无法使其正常工作,并怀疑有些奇怪的东西 该文件本身,我这次使用VIM直接在Mac上创建了一个新的。 我输入了完全相同的说明,...现在它可以使用 问题。
两个文件上的 diff 揭示了零差。

有什么区别?什么可以使第一个脚本不起作用?我怎么知道?

进行更新

在被接受的答案的建议之后,在错误的行之后 结局回来了,我检查了多件事。 事实证明,由于我从Windows复制了〜/.gitConfig 机器,我有 autocrlf = true ,所以每次修改bash 在Windows下的文件,它将行末尾重新设置为 \ r \ n
因此,除了运行 dos2unix (您必须 在Mac上使用HomeBrows安装),如果您使用的是Git,请检查您的 .gitConfig 文件。

I am making an NW.js app on macOS, and want to run the app in dev mode
by double-clicking on an icon.
In the first step, I'm trying to make my shell script work.

Using VS Code on Windows (I wanted to gain time), I have created a run-nw file at the root of my project, containing this:

#!/bin/bash

cd "src"
npm install

cd ..
./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &

but I get this output:

$ sh ./run-nw

: command not found  
: No such file or directory  
: command not found  
: No such file or directory  

Usage: npm <command>

where <command> is one of:  (snip commands list)

(snip npm help)

[email protected] /usr/local/lib/node_modules/npm  
: command not found  
: No such file or directory  
: command not found

Some things I don't understand.

  • It seems that it takes empty lines as commands.
    In my editor (VS Code) I have tried to replace \r\n with \n
    (in case the \r creates problems) but it changes nothing.
  • It seems that it doesn't find the folders
    (with or without the dirname instruction),
    or maybe it doesn't know about the cd command ?
  • It seems that it doesn't understand the install argument to npm.
  • The part that really weirds me out, is that it still runs the app
    (if I did an npm install manually)...

Not able to make it work properly, and suspecting something weird with
the file itself, I created a new one directly on the Mac, using vim this time.
I entered the exact same instructions, and... now it works without any
issues.
A diff on the two files reveals exactly zero difference.

What can be the difference? What can make the first script not work? How can I find out?

Update

Following the accepted answer's recommendations, after the wrong line
endings came back, I checked multiple things.
It turns out that since I copied my ~/.gitconfig from my Windows
machine, I had autocrlf=true, so every time I modified the bash
file under Windows, it re-set the line endings to \r\n.
So, in addition to running dos2unix (which you will have to
install using Homebrew on a Mac), if you're using Git, check your
.gitconfig file.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

天暗了我发光 2025-01-27 00:37:47

是的。 bash脚本在脚本本身和数据处理中都对线路末端敏感。它们应该具有Unix风格的线路端,即每条线均以线馈线(十进制10,ASCII中的十六进纸)终止。

脚本中的DOS/Windows线路结尾,

带有Windows或DOS风格的线路结尾,每条线均以托架返回终止,然后是线条供稿字符。您可以在 cat -v yourfile 的输出中看到此本来是看不见的字符:

$ cat -v yourfile
#!/bin/bash^M
^M
cd "src"^M
npm install^M
^M
cd ..^M
./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &^M

在这种情况下,在caret表示法中或^m /code>在c逃脱符号中)不被视为空格。 Bash将Shebang(由单个马车返回字符组成)之后解释为要运行的命令/程序的名称。

  • 由于没有命令名为^m ,它打印:找不到命令
  • 因为没有名称nate src^m ,它打印:没有这样的文件或目录
  • 它通过安装^m 而不是 install 作为引起的参数为 npm NPM 抱怨。

输入数据中的DOS/Windows行末尾

类似于上面的输入数据,如果您的输入文件带有收费返回:

hello^M
world^M

那么编辑器和将其写入屏幕时将看起来完全正常,但是工具可能会产生奇怪的结果。例如, grep 将无法找到显然存在的行:(

$ grep 'hello

因为该行实际上以^M 结束)

没有匹配, 马车返回将光标移动到行的开始:

$ sed -e 's/$/!/' file.txt
!ello
!orld

字符串比较将失败,即使在编写屏幕时字符串似乎是相同的:

$ a="hello"; read b < file.txt
$ if [[ "$a" = "$b" ]]
  then echo "Variables are equal."
  else echo "Sorry, $a is not equal to $b"
  fi

Sorry, hello is not equal to hello

解决方案

解决方案是将文件转换为使用Unix式的行末尾。有多种方法可以完成:

  1. 使用 dos2unix 程序:

      dos2unix文件名
     
  2. 在A 功能文本编辑器(Sublime,Notepad ++,Not Notepad)中打开文件,并将其配置为使用Unix line endings的文件,例如,使用vim,在保存之前运行以下命令:

     :设置fileformat = unix
     
  3. <<) P>如果您有 sed 实用程序的版本,该实用程序支持 -i - 现场选项,例如,gnu sed ,您可以运行以下命令来剥离尾随的马车返回:

      sed -i's/\ r $ //'fileName
     

    使用其他版本的 sed ,您可以使用输出重定向写入新文件。确保将其他文件名用于重定向目标(以后可以重命名)。

      sed's/\ r $ //'fileName&gt; filename.unix
     
  4. 同样, tr 翻译过滤器可用于从其输入中删除不需要的字符:

      tr -d'\ r'&lt; filename&gt; filename.unix
     

cygwin bash

带有bash端口的cygwin,有一个自定义 igncr 选项,可以将其设置为忽略线路结尾的运输返回(大概是因为其许多用户使用本机Windows程序来编辑其文本文件)。
可以通过运行 set -o igncr 来为当前 shell启用这一点。

设置此选项仅适用于 current shell进程,因此当 sourcing 文件带有无关的托架返回时,它可以很有用。如果您定期遇到具有DOS线结尾的Shell脚本,并希望永久设置此选项,则可以设置一个称为 shellOpts (所有大写字母)的环境变量,以包括 igncr 。 Bash使用此环境变量在启动时将其设置为设置Shell选项(在读取任何启动文件之前)。

有用的实用程序

文件实用程序对于快速查看文本文件中使用了哪些线路结尾。这是针对每种文件类型打印的内容:

  • unix行末尾: bourne-again as shell脚本,ascii文本可执行文件
  • mac line endings: bourne-again as shell shell脚本,ascii文本可执行,带有CR行terminators
  • dos行末尾: bourne-again as shell脚本,ASCII文本可执行文件,带有CRLF行终端

cat> cat 实用程序的GNU版本具有 - - v, - 显示非打印字符的表 - 非打印选项。

dos2unix 实用程序是专门编写的,用于在UNIX,MAC和DOS线结束之间转换文本文件。

有用的链接

Wikipedia具有出色的文章涵盖了标记文本线结束的许多不同方法,此类编码的历史以及如何在不同的操作系统,编程语言和Internet协议(例如FTP)中处理新线。

带有经典Mac OS线路结尾的文件,

classic mac os (pre-os x),每行都是终止于马车返回(十进制13,ASCII中的十六进制)。如果脚本文件用这样的行结尾保存,BASH只会看到一条长行:

#!/bin/bash^M^Mcd "src"^Mnpm install^M^Mcd ..^M./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &^M

因为这条长线以Octothorpe()开始)作为一个评论。

注意:2001年,Apple启动了基于BSD衍生的 nextStep 操作系统操作系统的Mac OS X 。结果,OS X还使用UNIX风格的仅限LF线结尾,从那时起,用CR终止的文本文件变得极为罕见。尽管如此,我认为值得展示Bash将如何尝试解释此类文件。

file.txt || grep -x "hello" file.txt $

因为该行实际上以^M 结束)

没有匹配, 马车返回将光标移动到行的开始:


字符串比较将失败,即使在编写屏幕时字符串似乎是相同的:


解决方案

解决方案是将文件转换为使用Unix式的行末尾。有多种方法可以完成:

  1. 使用 dos2unix 程序:

    
    
  2. 在A 功能文本编辑器(Sublime,Notepad ++,Not Notepad)中打开文件,并将其配置为使用Unix line endings的文件,例如,使用vim,在保存之前运行以下命令:

    
    
  3. <<) P>如果您有 sed 实用程序的版本,该实用程序支持 -i - 现场选项,例如,gnu sed ,您可以运行以下命令来剥离尾随的马车返回:

    
    

    使用其他版本的 sed ,您可以使用输出重定向写入新文件。确保将其他文件名用于重定向目标(以后可以重命名)。

    
    
  4. 同样, tr 翻译过滤器可用于从其输入中删除不需要的字符:

    
    

cygwin bash

带有bash端口的cygwin,有一个自定义 igncr 选项,可以将其设置为忽略线路结尾的运输返回(大概是因为其许多用户使用本机Windows程序来编辑其文本文件)。
可以通过运行 set -o igncr 来为当前 shell启用这一点。

设置此选项仅适用于 current shell进程,因此当 sourcing 文件带有无关的托架返回时,它可以很有用。如果您定期遇到具有DOS线结尾的Shell脚本,并希望永久设置此选项,则可以设置一个称为 shellOpts (所有大写字母)的环境变量,以包括 igncr 。 Bash使用此环境变量在启动时将其设置为设置Shell选项(在读取任何启动文件之前)。

有用的实用程序

文件实用程序对于快速查看文本文件中使用了哪些线路结尾。这是针对每种文件类型打印的内容:

  • unix行末尾: bourne-again as shell脚本,ascii文本可执行文件
  • mac line endings: bourne-again as shell shell脚本,ascii文本可执行,带有CR行terminators
  • dos行末尾: bourne-again as shell脚本,ASCII文本可执行文件,带有CRLF行终端

cat> cat 实用程序的GNU版本具有 - - v, - 显示非打印字符的表 - 非打印选项。

dos2unix 实用程序是专门编写的,用于在UNIX,MAC和DOS线结束之间转换文本文件。

有用的链接

Wikipedia具有出色的文章涵盖了标记文本线结束的许多不同方法,此类编码的历史以及如何在不同的操作系统,编程语言和Internet协议(例如FTP)中处理新线。

带有经典Mac OS线路结尾的文件,

classic mac os (pre-os x),每行都是终止于马车返回(十进制13,ASCII中的十六进制)。如果脚本文件用这样的行结尾保存,BASH只会看到一条长行:


因为这条长线以Octothorpe()开始)作为一个评论。

注意:2001年,Apple启动了基于BSD衍生的 nextStep 操作系统操作系统的Mac OS X 。结果,OS X还使用UNIX风格的仅限LF线结尾,从那时起,用CR终止的文本文件变得极为罕见。尽管如此,我认为值得展示Bash将如何尝试解释此类文件。

Yes. Bash scripts are sensitive to line-endings, both in the script itself and in data it processes. They should have Unix-style line-endings, i.e., each line is terminated with a Line Feed character (decimal 10, hex 0A in ASCII).

DOS/Windows line endings in the script

With Windows or DOS-style line endings , each line is terminated with a Carriage Return followed by a Line Feed character. You can see this otherwise invisible character in the output of cat -v yourfile:

$ cat -v yourfile
#!/bin/bash^M
^M
cd "src"^M
npm install^M
^M
cd ..^M
./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &^M

In this case, the carriage return (^M in caret notation or \r in C escape notation) is not treated as whitespace. Bash interprets the first line after the shebang (consisting of a single carriage return character) as the name of a command/program to run.

  • Since there is no command named ^M, it prints : command not found
  • Since there is no directory named src^M, it prints : No such file or directory
  • It passes install^M instead of install as an argument to npm which causes npm to complain.

DOS/Windows line endings in input data

Like above, if you have an input file with carriage returns:

hello^M
world^M

then it will look completely normal in editors and when writing it to screen, but tools may produce strange results. For example, grep will fail to find lines that are obviously there:

$ grep 'hello

(no match because the line actually ends in ^M)

Appended text will seem to overwrite the line because the carriage return moves the cursor to the start of the line:

$ sed -e 's/$/!/' file.txt
!ello
!orld

String comparison will fail, even though strings appear to be the same when writing to screen:

$ a="hello"; read b < file.txt
$ if [[ "$a" = "$b" ]]
  then echo "Variables are equal."
  else echo "Sorry, $a is not equal to $b"
  fi

Sorry, hello is not equal to hello

Solutions

The solution is to convert the file to use Unix-style line endings. There are a number of ways this can be accomplished:

  1. Using the dos2unix program:

    dos2unix filename
    
  2. Open the file in a capable text editor (Sublime, Notepad++, not Notepad) and configure it to save files with Unix line endings, e.g., with Vim, run the following command before (re)saving:

    :set fileformat=unix
    
  3. If you have a version of the sed utility that supports the -i or --in-place option, e.g., GNU sed, you could run the following command to strip trailing carriage returns:

    sed -i 's/\r$//' filename
    

    With other versions of sed, you could use output redirection to write to a new file. Be sure to use a different filename for the redirection target (it can be renamed later).

    sed 's/\r$//' filename > filename.unix
    
  4. Similarly, the tr translation filter can be used to delete unwanted characters from its input:

    tr -d '\r' <filename >filename.unix
    

Cygwin Bash

With the Bash port for Cygwin, there’s a custom igncr option that can be set to ignore the Carriage Return in line endings (presumably because many of its users use native Windows programs to edit their text files).
This can be enabled for the current shell by running set -o igncr.

Setting this option applies only to the current shell process so it can be useful when sourcing files with extraneous carriage returns. If you regularly encounter shell scripts with DOS line endings and want this option to be set permanently, you could set an environment variable called SHELLOPTS (all capital letters) to include igncr. This environment variable is used by Bash to set shell options when it starts (before reading any startup files).

Useful utilities

The file utility is useful for quickly seeing which line endings are used in a text file. Here’s what it prints for for each file type:

  • Unix line endings: Bourne-Again shell script, ASCII text executable
  • Mac line endings: Bourne-Again shell script, ASCII text executable, with CR line terminators
  • DOS line endings: Bourne-Again shell script, ASCII text executable, with CRLF line terminators

The GNU version of the cat utility has a -v, --show-nonprinting option that displays non-printing characters.

The dos2unix utility is specifically written for converting text files between Unix, Mac and DOS line endings.

Useful links

Wikipedia has an excellent article covering the many different ways of marking the end of a line of text, the history of such encodings and how newlines are treated in different operating systems, programming languages and Internet protocols (e.g., FTP).

Files with classic Mac OS line endings

With Classic Mac OS (pre-OS X), each line was terminated with a Carriage Return (decimal 13, hex 0D in ASCII). If a script file was saved with such line endings, Bash would only see one long line like so:

#!/bin/bash^M^Mcd "src"^Mnpm install^M^Mcd ..^M./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &^M

Since this single long line begins with an octothorpe (#), Bash treats the line (and the whole file) as a single comment.

Note: In 2001, Apple launched Mac OS X which was based on the BSD-derived NeXTSTEP operating system. As a result, OS X also uses Unix-style LF-only line endings and since then, text files terminated with a CR have become extremely rare. Nevertheless, I think it’s worthwhile to show how Bash would attempt to interpret such files.

file.txt || grep -x "hello" file.txt $

(no match because the line actually ends in ^M)

Appended text will seem to overwrite the line because the carriage return moves the cursor to the start of the line:


String comparison will fail, even though strings appear to be the same when writing to screen:


Solutions

The solution is to convert the file to use Unix-style line endings. There are a number of ways this can be accomplished:

  1. Using the dos2unix program:

    
    
  2. Open the file in a capable text editor (Sublime, Notepad++, not Notepad) and configure it to save files with Unix line endings, e.g., with Vim, run the following command before (re)saving:

    
    
  3. If you have a version of the sed utility that supports the -i or --in-place option, e.g., GNU sed, you could run the following command to strip trailing carriage returns:

    
    

    With other versions of sed, you could use output redirection to write to a new file. Be sure to use a different filename for the redirection target (it can be renamed later).

    
    
  4. Similarly, the tr translation filter can be used to delete unwanted characters from its input:

    
    

Cygwin Bash

With the Bash port for Cygwin, there’s a custom igncr option that can be set to ignore the Carriage Return in line endings (presumably because many of its users use native Windows programs to edit their text files).
This can be enabled for the current shell by running set -o igncr.

Setting this option applies only to the current shell process so it can be useful when sourcing files with extraneous carriage returns. If you regularly encounter shell scripts with DOS line endings and want this option to be set permanently, you could set an environment variable called SHELLOPTS (all capital letters) to include igncr. This environment variable is used by Bash to set shell options when it starts (before reading any startup files).

Useful utilities

The file utility is useful for quickly seeing which line endings are used in a text file. Here’s what it prints for for each file type:

  • Unix line endings: Bourne-Again shell script, ASCII text executable
  • Mac line endings: Bourne-Again shell script, ASCII text executable, with CR line terminators
  • DOS line endings: Bourne-Again shell script, ASCII text executable, with CRLF line terminators

The GNU version of the cat utility has a -v, --show-nonprinting option that displays non-printing characters.

The dos2unix utility is specifically written for converting text files between Unix, Mac and DOS line endings.

Useful links

Wikipedia has an excellent article covering the many different ways of marking the end of a line of text, the history of such encodings and how newlines are treated in different operating systems, programming languages and Internet protocols (e.g., FTP).

Files with classic Mac OS line endings

With Classic Mac OS (pre-OS X), each line was terminated with a Carriage Return (decimal 13, hex 0D in ASCII). If a script file was saved with such line endings, Bash would only see one long line like so:


Since this single long line begins with an octothorpe (#), Bash treats the line (and the whole file) as a single comment.

Note: In 2001, Apple launched Mac OS X which was based on the BSD-derived NeXTSTEP operating system. As a result, OS X also uses Unix-style LF-only line endings and since then, text files terminated with a CR have become extremely rare. Nevertheless, I think it’s worthwhile to show how Bash would attempt to interpret such files.

勿忘初心 2025-01-27 00:37:47

在 JetBrains 产品(PyCharm、PHPStorm、IDEA 等)中,您需要单击 CRLF/LF 在两者之间切换行分隔符的类型(\r\n\n)。

屏幕截图显示在状态栏中选择 LF

显示在状态栏中选择 CRLF 的屏幕截图

In JetBrains products (PyCharm, PHPStorm, IDEA, etc.), you'll need to click on CRLF/LF to toggle between the two types of line separators (\r\n and \n).

screenshot showing LF selected in the status bar

screenshot showing CRLF selected in the status bar

等你爱我 2025-01-27 00:37:47

我试图从 Windows 启动我的 Docker 容器,结果发现:

Bash script and /bin/bash^M: bad interpreter: No such file or directory

我正在使用 Git Bash,问题出在 Git 配置上,然后我执行了以下步骤,结果成功了。它将配置 Git 在签出时不转换行结尾:

  1. git config --global core.autocrlf input
  2. 删除本地存储库
  3. 并再次克隆它。

非常感谢 Jason Harmon 在此链接中:
https://forums.docker。 com/t/error-while-running-docker-code-in-powershell/34059/6

在此之前,我尝试过这个,但不起作用:

  1. dos2unix scriptname.sh
  2. sed -i -e 's/\r$//' scriptname.sh
  3. sed -i -e 's/^M$//' 脚本名。嘘

I was trying to startup my Docker container from Windows and got this:

Bash script and /bin/bash^M: bad interpreter: No such file or directory

I was using Git Bash and the problem was with the Git config, then I just did the steps below and it worked. It will configure Git to not convert line endings on checkout:

  1. git config --global core.autocrlf input
  2. delete your local repository
  3. clone it again.

Many thanks to Jason Harmon in this link:
https://forums.docker.com/t/error-while-running-docker-code-in-powershell/34059/6

Before that, I tried this, that didn't work:

  1. dos2unix scriptname.sh
  2. sed -i -e 's/\r$//' scriptname.sh
  3. sed -i -e 's/^M$//' scriptname.sh
烟凡古楼 2025-01-27 00:37:47

如果您使用的读取将从线的开头和结尾修剪空格。如果您告诉它,马车返回是空格的(通过将它们添加到 ifs 变量中),它将从线的末端修剪它们。

在bash(或zsh或ksh)中,这意味着您要替换此标准成语:(

IFS= read -r somevar    # This will not trim CR

注意: -r 选项与此

IFS=

无关,这通常是一个好主意避免撞击。)

如果您不使用 ifs = 前缀(例如,因为要将数据拆分为字段),那么您将替换以下:

read -r field1 field2 ...    # This will not trim CR

如果您正在使用:

IFS=

如果您正在使用不支持 $'...''引用模式的外壳(例如,dash,某些Linux发行版上的默认/bin/sh),或者您的脚本甚至可能用这样的外壳运行,然后您需要变得更加复杂:

cr="$(printf '\r')"
IFS="$cr" read -r somevar    # Read trimming *only* CR
IFS="$IFS$cr" read -r field1 field2 ...    # Read trimming CR and whitespace, and splitting fields

请注意,通常,当您更改 ifs 时,应该尽快将其放回正常状态以避免奇怪的副作用;但是,在所有这些情况下,它都是 read 命令的前缀,因此它仅影响一个命令,而不必在之后重置。

\r' read -r somevar # This *will* trim CR

无关,这通常是一个好主意避免撞击。)

如果您不使用 ifs = 前缀(例如,因为要将数据拆分为字段),那么您将替换以下:


如果您正在使用:


如果您正在使用不支持 $'...''引用模式的外壳(例如,dash,某些Linux发行版上的默认/bin/sh),或者您的脚本甚至可能用这样的外壳运行,然后您需要变得更加复杂:


请注意,通常,当您更改 ifs 时,应该尽快将其放回正常状态以避免奇怪的副作用;但是,在所有这些情况下,它都是 read 命令的前缀,因此它仅影响一个命令,而不必在之后重置。

\t\n\r' read -r field1 field2 ... # This *will* trim CR

如果您正在使用不支持 $'...''引用模式的外壳(例如,dash,某些Linux发行版上的默认/bin/sh),或者您的脚本甚至可能用这样的外壳运行,然后您需要变得更加复杂:


请注意,通常,当您更改 ifs 时,应该尽快将其放回正常状态以避免奇怪的副作用;但是,在所有这些情况下,它都是 read 命令的前缀,因此它仅影响一个命令,而不必在之后重置。

\r' read -r somevar # This *will* trim CR

无关,这通常是一个好主意避免撞击。)

如果您不使用 ifs = 前缀(例如,因为要将数据拆分为字段),那么您将替换以下:


如果您正在使用:


如果您正在使用不支持 $'...''引用模式的外壳(例如,dash,某些Linux发行版上的默认/bin/sh),或者您的脚本甚至可能用这样的外壳运行,然后您需要变得更加复杂:


请注意,通常,当您更改 ifs 时,应该尽快将其放回正常状态以避免奇怪的副作用;但是,在所有这些情况下,它都是 read 命令的前缀,因此它仅影响一个命令,而不必在之后重置。

If you're using the read command to read from a file (or pipe) that is (or might be) in DOS/Windows format, you can take advantage of the fact that read will trim whitespace from the beginning and ends of lines. If you tell it that carriage returns are whitespace (by adding them to the IFS variable), it'll trim them from the ends of lines.

In bash (or zsh or ksh), that means you'd replace this standard idiom:

IFS= read -r somevar    # This will not trim CR

with this:

IFS=

(Note: the -r option isn't related to this, it's just usually a good idea to avoid mangling backslashes.)

If you're not using the IFS= prefix (e.g. because you want to split the data into fields), then you'd replace this:

read -r field1 field2 ...    # This will not trim CR

with this:

IFS=

If you're using a shell that doesn't support the $'...' quoting mode (e.g. dash, the default /bin/sh on some Linux distros), or your script even might be run with such a shell, then you need to get a little more complex:

cr="$(printf '\r')"
IFS="$cr" read -r somevar    # Read trimming *only* CR
IFS="$IFS$cr" read -r field1 field2 ...    # Read trimming CR and whitespace, and splitting fields

Note that normally, when you change IFS, you should put it back to normal as soon as possible to avoid weird side effects; but in all these cases, it's a prefix to the read command, so it only affects that one command and doesn't have to be reset afterward.

\r' read -r somevar # This *will* trim CR

(Note: the -r option isn't related to this, it's just usually a good idea to avoid mangling backslashes.)

If you're not using the IFS= prefix (e.g. because you want to split the data into fields), then you'd replace this:


with this:


If you're using a shell that doesn't support the $'...' quoting mode (e.g. dash, the default /bin/sh on some Linux distros), or your script even might be run with such a shell, then you need to get a little more complex:


Note that normally, when you change IFS, you should put it back to normal as soon as possible to avoid weird side effects; but in all these cases, it's a prefix to the read command, so it only affects that one command and doesn't have to be reset afterward.

\t\n\r' read -r field1 field2 ... # This *will* trim CR

If you're using a shell that doesn't support the $'...' quoting mode (e.g. dash, the default /bin/sh on some Linux distros), or your script even might be run with such a shell, then you need to get a little more complex:


Note that normally, when you change IFS, you should put it back to normal as soon as possible to avoid weird side effects; but in all these cases, it's a prefix to the read command, so it only affects that one command and doesn't have to be reset afterward.

\r' read -r somevar # This *will* trim CR

(Note: the -r option isn't related to this, it's just usually a good idea to avoid mangling backslashes.)

If you're not using the IFS= prefix (e.g. because you want to split the data into fields), then you'd replace this:


with this:


If you're using a shell that doesn't support the $'...' quoting mode (e.g. dash, the default /bin/sh on some Linux distros), or your script even might be run with such a shell, then you need to get a little more complex:


Note that normally, when you change IFS, you should put it back to normal as soon as possible to avoid weird side effects; but in all these cases, it's a prefix to the read command, so it only affects that one command and doesn't have to be reset afterward.

愛放△進行李 2025-01-27 00:37:47

由于正在使用 VS Code,我们可以在右下角看到 CRLF 或 LF,具体取决于所使用的内容,如果单击它,我们可以在它们之间进行更改(在下面的示例中使用 LF):

快捷方式 UI 屏幕截图

我们还可以使用命令托盘中的“更改行尾序列”命令。因为它们的功能相同,所以更容易记住。

Since VS Code is being used, we can see CRLF or LF in the bottom right depending on what's being used and if we click on it we can change between them (LF is being used in below example):

Screenshot of shortcut UI

We can also use the "Change End of Line Sequence" command from the command pallet. Whatever's easier to remember since they're functionally the same.

紫南 2025-01-27 00:37:47

来自重复项,如果问题是您的文件名称末尾包含^M,您可以将它们重命名为“

for f in *

您正确地想要修复导致这些文件的任何原因”首先要使用损坏的名称(可能创建它们的脚本应该进行 dos2unix 编辑,然后重新运行?),但有时这是不可行的。

$'\r' 语法是 Bash 特定的;如果您有不同的外壳,也许您需要使用其他符号。也许另请参阅 sh 和 bash 之间的区别

\r'; do mv "$f" "${f%

您正确地想要修复导致这些文件的任何原因”首先要使用损坏的名称(可能创建它们的脚本应该进行 dos2unix 编辑,然后重新运行?),但有时这是不可行的。

$'\r' 语法是 Bash 特定的;如果您有不同的外壳,也许您需要使用其他符号。也许另请参阅 sh 和 bash 之间的区别

\r'}" done

您正确地想要修复导致这些文件的任何原因”首先要使用损坏的名称(可能创建它们的脚本应该进行 dos2unix 编辑,然后重新运行?),但有时这是不可行的。

$'\r' 语法是 Bash 特定的;如果您有不同的外壳,也许您需要使用其他符号。也许另请参阅 sh 和 bash 之间的区别

Coming from a duplicate, if the problem is that you have files whose names contain ^M at the end, you can rename them with

for f in *

You properly want to fix whatever caused these files to have broken names in the first place (probably a script which created them should be dos2unixed and then rerun?) but sometimes this is not feasible.

The $'\r' syntax is Bash-specific; if you have a different shell, maybe you need to use some other notation. Perhaps see also Difference between sh and bash

\r'; do mv "$f" "${f%

You properly want to fix whatever caused these files to have broken names in the first place (probably a script which created them should be dos2unixed and then rerun?) but sometimes this is not feasible.

The $'\r' syntax is Bash-specific; if you have a different shell, maybe you need to use some other notation. Perhaps see also Difference between sh and bash

\r'}" done

You properly want to fix whatever caused these files to have broken names in the first place (probably a script which created them should be dos2unixed and then rerun?) but sometimes this is not feasible.

The $'\r' syntax is Bash-specific; if you have a different shell, maybe you need to use some other notation. Perhaps see also Difference between sh and bash

思念绕指尖 2025-01-27 00:37:47

当我将 git 与 WSL 结合使用时,我遇到了这个问题。
git 有一个功能,它可以根据您使用的操作系统更改文件的行结尾,在 Windows 上,它确保行结尾为 \r\n ,这与仅使用 Linux 的 Linux 不兼容<代码>\n

您可以通过将文件名 .gitattributes 添加到 git 根目录并添加如下行来解决此问题:

config/* text eol=lf
run.sh text eol=lf

在此示例中,config 目录中的所有文件都只有行- feed 行结尾和 run.sh 文件也是如此。

I ran into this issue when I use git with WSL.
git has a feature where it changes the line-ending of files according to the OS you are using, on Windows it make sure the line endings are \r\n which is not compatible with Linux which uses only \n.

You can resolve this problem by adding a file name .gitattributes to your git root directory and add lines as following:

config/* text eol=lf
run.sh text eol=lf

In this example all files inside config directory will have only line-feed line ending and run.sh file as well.

对你再特殊 2025-01-27 00:37:47

大量参考 git,但没有重新规范化行结尾。只需转到存储库的根目录并运行:

git add --renormalize .

仅重新签入需要刷新行结尾的文件。文件看起来没有任何更改,因为行结尾是不可见的。

Lots of reference to git but not to renormalizing the line endings in place. Just go to the root of your repo and run:

git add --renormalize .

Only the files that need line endings refreshed will be re-checked in. It will appear that the files have no changes, because line endings are invisible.

喵星人汪星人 2025-01-27 00:37:47

对于记事本++用户,可以通过: edit &gt; eol conversion &gt; unix(lf)

”屏幕截图上述步骤“

For Notepad++ users, this can be solved by: Edit > EOL Conversion > Unix (LF)

screenshot showing above steps

寄风 2025-01-27 00:37:47

删除不需要的 CR ('\r') 字符的另一种方法是运行 tr 命令,例如:

$ tr -d '\r' < dosScript.py > nixScript.py

One more way to get rid of the unwanted CR ('\r') character is to run the tr command, for example:

$ tr -d '\r' < dosScript.py > nixScript.py
如梦亦如幻 2025-01-27 00:37:47

Mac / Linux上的最简单方法 - 使用“ touch”命令创建文件,使用VI或VIM编辑器打开此文件,粘贴您的代码并保存。这将自动删除Windows字符。

The simplest way on MAC / Linux - create a file using 'touch' command, open this file with VI or VIM editor, paste your code and save. This would automatically remove the windows characters.

呆萌少年 2025-01-27 00:37:47

如果您使用的是像BBEDIT这样的文本编辑器,则可以在状态栏上进行。有一个选择可以切换。

If you are using a text editor like BBEdit you can do it at the status bar. There is a selection where you can switch.

Change the CRLF to LF using BBEdit

许一世地老天荒 2025-01-27 00:37:47

脚本可以互相打电话。
一个更好的魔术解决方案是将文件夹/子文件夹中的所有脚本转换:

find . -name "*.sh" -exec sed -i -e 's/\r$//' {} +

您也可以使用 dos2unix ,但是默认情况下,许多服务器都没有安装它。

Scripts may call each other.
An even better magic solution is to convert all scripts in the folder/subfolders:

find . -name "*.sh" -exec sed -i -e 's/\r$//' {} +

You can use dos2unix too but many servers do not have it installed by default.

思念绕指尖 2025-01-27 00:37:47

与这个问题相比,我曾多次损坏Bash脚本。

关于如何更改文件的解决方案已经发布了许多解决方案。
不过,我在内置的VIM方法上没有看到任何执行此任务的方法。

使用shell脚本打开vim并运行此命令

:set ff=unix

,然后编辑您的.gitAttributes以获取永久修复程序

I've had corrupted bash scripts so many times from this issue.

There are already many solutions posted on how to change the file.
Though, I didn't see any on the built-in vim method to do this task.

Open vim with the shell script and run this command

:set ff=unix

Then edit your .gitattributes to get a permanent fix

妥活 2025-01-27 00:37:47

对于Intellij用户,这是编写Linux脚本的解决方案: file &gt; 线分离器
使用 lf -unix和macOS(\ n)

”屏幕截图上述步骤“

For IntelliJ users, here is the solution for writing Linux script: File > Line Separators
Use LF - Unix and macOS (\n)

screenshot showing above steps

神经暖 2025-01-27 00:37:47

以防万一,如果您(像我一样)需要一个可在 Windows 中编辑但可在 Linux 中运行的脚本(因此该脚本可能有 CRLF,并且我们不能有 2 个版本,一个用于 Linux,另一个用于 Windows),我来到了在Linux中运行脚本的方式如下(./build.sh是脚本)

sed -e 's/\r$//' ./build.sh | bash

Just in case if you (like me) need to have a script editable in Windows, but runnable in Linux (so the script MAY have CRLF, and we cannot have 2 versions, one for Linux, another for Windows), I came to the following way of running the script in Linux (./build.sh is the script)

sed -e 's/\r$//' ./build.sh | bash
醉城メ夜风 2025-01-27 00:37:47

如果您收到错误消息

/usr/bin/env: 'bash\r': 没有这样的文件或目录

这通常是因为您调用的脚本嵌入了 \r 字符,这反过来表明它具有 Windows 风格的 \r\n 行结尾(换行符),而不是 bash 期望的仅 \n 行结尾

您需要“重置”环境变量以确保您使用默认环境设置。这可以通过在终端中运行以下命令来完成:

source /etc/profile
source ~/.bashrc
source ~/.profile

您可以通过打开终端来运行这些命令,或者如果您使用的是 WSL,则可以通过连接到 WSL 实例来执行命令。

If you are getting an error saying

/usr/bin/env: ‘bash\r’: No such file or directory

It generally happens because the script you're invoking has embedded \r characters, which in turn suggests that it has Windows-style \r\n line endings (newlines) instead of the \n-only line endings bash expects

You need to "reset" the environment variables to ensure that you are using the default environment settings. This can be done by running the following command in your terminal:

source /etc/profile
source ~/.bashrc
source ~/.profile

You can run these commands by opening a terminal or, if you are using WSL, by connecting to your WSL instance to execute the commands.

萧瑟寒风 2025-01-27 00:37:47

为了完整起见,我将指出 另一种解决方案这可以永久解决这个问题,而不需要一直运行 dos2unix:

sudo ln -s /bin/bash `printf 'bash\r'`

For the sake of completeness, I'll point out another solution which can solve this problem permanently without the need to run dos2unix all the time:

sudo ln -s /bin/bash `printf 'bash\r'`
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文