BASH:从字符串中去除换行符(读取行)

发布于 2024-08-05 08:04:09 字数 779 浏览 5 评论 0原文

我遇到了以下问题:我正在编写一个 Linux bash 脚本,该脚本执行以下操作:

  • 从文件中读取行
  • 从刚刚读取的行末尾去除 \n 字符
  • 执行其中的命令

例子: Commands.txt

ls
ls -l
ls -ltra
ps as

bash 文件的执行应该获取第一行并执行它,但是当 \n 存在时,shell 只输出“command not find: ls” 脚本的那部分看起来像这样

 read line

        if [ -n "$line" ]; then #if not empty line

                #myline=`echo -n $line | tr -d '\n'`
                #myline=`echo -e $line | sed ':start /^.*$/N;s/\n//g; t start'`

                myline=`echo -n $line | tr -d "\n"`
                $myline  #execute it

                cat $fname | tail -n+2 > $fname.txt
                mv $fname.txt $fname
        fi

评论你在询问之前已经尝试过的事情。有什么解决办法吗?过去几个小时我都在为这事绞尽脑汁……

I bumped into the following problem: I'm writing a Linux bash script which does the following:

  • Read line from file
  • Strip the \n character from the end of the line just read
  • Execute the command that's in there

Example:
commands.txt

ls
ls -l
ls -ltra
ps as

The execution of the bash file should get the first line, and execute it, but while the \n present, the shell just outputs "command not found: ls"
That part of the script looks like this

 read line

        if [ -n "$line" ]; then #if not empty line

                #myline=`echo -n $line | tr -d '\n'`
                #myline=`echo -e $line | sed ':start /^.*$/N;s/\n//g; t start'`

                myline=`echo -n $line | tr -d "\n"`
                $myline  #execute it

                cat $fname | tail -n+2 > $fname.txt
                mv $fname.txt $fname
        fi

Commented you have the things I tried before asking SO. Any solutions? I'm smashing my brains for the last couple of hours over this...

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

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

发布评论

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

评论(7

雨落□心尘 2024-08-12 08:04:09

我总是喜欢 perl -ne 'chomp and print' 来修剪换行符。很好而且很容易记住。

例如 ls -l | perl -ne 'chomp and print'

但是

我不认为这是你的问题。尽管我不确定我是否理解您如何将文件中的命令传递给 shell 脚本中的“读取”。

使用我自己的测试脚本(test.sh)

read line
if [ -n "$line" ]; then
  $line
fi

和示例输入文件(test.cmds)

ls 
ls -l
ls -ltra

如果我像这样运行它 ./test.sh ./test.sh < test.cmds,我看到了预期的结果,即在当前工作目录上运行第一个命令“ls”。

也许您的输入文件中有其他不可打印的字符?

我的看起来像这样

od -c test.cmds 
0000000    l   s      \n   l   s       -   l  \n   l   s       -   l   t
0000020    r   a  \n                                                    
0000023

从下面的评论中,我怀疑您的输入文件中可能有回车符(“\r”),这与换行符不同。输入文件原来是DOS格式的吗?如果是这样,那么您需要将以“\r\n”结尾的 2 字节 DOS 行转换为单字节 UNIX 行“\n”才能达到预期结果。

您应该可以通过在任何注释掉的行中将“\n”替换为“\r”来完成此操作。

I always like perl -ne 'chomp and print' , for trimming newlines. Nice and easy to remember.

e.g. ls -l | perl -ne 'chomp and print'

However

I don't think that is your problem here though. Although I'm not sure I understand how you're passing the commands in the file through to the 'read' in your shell script.

With a test script of my own like this (test.sh)

read line
if [ -n "$line" ]; then
  $line
fi

and a sample input file like this (test.cmds)

ls 
ls -l
ls -ltra

If I run it like this ./test.sh < test.cmds, I see the expected result, which is to run the first command 'ls' on the current working directory.

Perhaps your input file has additional non-printable characters in it ?

mine looks like this

od -c test.cmds 
0000000    l   s      \n   l   s       -   l  \n   l   s       -   l   t
0000020    r   a  \n                                                    
0000023

From your comments below, I suspect you may have carriage returns ( "\r" ) in your input file, which is not the same thing as a newline. Is the input file originally in DOS format ? If so, then you need to convert the 2 byte DOS line ending "\r\n" to the single byte UNIX one, "\n" to achieve the expected results.

You should be able to do this by swapping the "\n" for "\r" in any of your commented out lines.

芯好空 2024-08-12 08:04:09

有人已经编写了一个执行 shell 命令的程序: sh file

如果您确实只想执行文件的第一行: head -n 1 file |sh

如果您的问题是回车符: tr -d '\r' <文件 |sh

Someone already wrote a program which executes shell commands: sh file

If you really only want to execute the first line of a file: head -n 1 file |sh

If your problem is carriage-returns: tr -d '\r' <file |sh

醉酒的小男人 2024-08-12 08:04:09

您还可以尝试仅使用 Bash 内置命令将回车符替换为换行符:

line=
a line\r' 
line="${line//
\r'/
\n'}" 
#line="${line/%
\r'/
\n'}"       # replace only at line end
printf "%s" "$line" | ruby -0777 -n -e 'p $_.to_s' 

You may also try to replace carriage returns with newlines only using Bash builtins:

line=
a line\r' 
line="${line//
\r'/
\n'}" 
#line="${line/%
\r'/
\n'}"       # replace only at line end
printf "%s" "$line" | ruby -0777 -n -e 'p $_.to_s' 
鲜血染红嫁衣 2024-08-12 08:04:09

我尝试了以下操作:

read line
echo -n $line | od -x

对于输入“xxxx”,我得到:

0000000 7878 7878

如您所见,变量内容的末尾没有 \n 。我建议使用选项-xbash -x script)运行脚本。这将在执行时打印所有命令。

[编辑] 您的问题是您在Windows 上编辑了commands.txt。现在,该文件包含 CRLF (0d0a) 作为行分隔符,这会混淆 read(并且 ls\r 不是已知命令)。使用 dos2unix 或类似工具将其转换为 Unix 文件。

I tried this:

read line
echo -n $line | od -x

For the input 'xxxx', I get:

0000000 7878 7878

As you can see, there is no \n at the end of the contents of the variable. I suggest to run the script with the option -x (bash -x script). This will print all commands as they are executed.

[EDIT] Your problem is that you edited commands.txt on Windows. Now, the file contains CRLF (0d0a) as line delimiters which confuses read (and ls\r is not a known command). Use dos2unix or similar to turn it into a Unix file.

软的没边 2024-08-12 08:04:09

你需要 eval 命令,


#!/bin/bash -x

while read  cmd
do
 if [ "$cmd" ]
 then
  eval "$cmd"
 fi
done

我将其运行为
./script.sh < file.txt 文件

.txt 是:

ls
ls -l
ls -ltra
ps as

you need eval command


#!/bin/bash -x

while read  cmd
do
 if [ "$cmd" ]
 then
  eval "$cmd"
 fi
done

I ran it as
./script.sh < file.txt

And file.txt was:

ls
ls -l
ls -ltra
ps as
少钕鈤記 2024-08-12 08:04:09

虽然不适用于 ls,但我建议您查看 查找-print0选项

though not working for ls, I recommend having a look at find’s -print0 option

李不 2024-08-12 08:04:09

以下脚本有效(至少对我来说):

#!/bin/bash

while read I ; do if [ "$I" ] ; then $I ; fi ; done ;

The following script works (at least for me):

#!/bin/bash

while read I ; do if [ "$I" ] ; then $I ; fi ; done ;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文