从字符串中去掉换行符(read line):BASH

12

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

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

例如: commands.txt

ls
ls -l
ls -ltra
ps as

执行bash文件应该获取第一行并执行,但是由于存在 \n ,所以shell会输出 "command not found: 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

在向SO提问之前,我已经尝试过一些方法。有解决方案吗?我已经为此苦思冥想了几个小时...


你是否尝试过仅使用$line - knittl
当然了。但是它显示“未找到命令:ls”。 - Bogdan Constantinescu
所需的只是:myline="$(echo -n "$line)")"(如果您想要,可以使用反引号而不是 $())。 - We Are All Monica
7个回答

18
我总是喜欢使用perl -ne 'chomp and print'来删除换行符,这样做简单易记。
例如:ls -l | perl -ne 'chomp and print' 不过,我不认为这是你的问题。虽然我不确定你是如何将文件中的命令传递给shell脚本中的'read'的。
我自己编写了一个测试脚本(test.sh):
read line
if [ -n "$line" ]; then
  $line
fi

以下是一个样本输入文件(test.cmds)

ls 
ls -l
ls -ltra

如果我像这样运行它:./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格式下吗?如果是,则需要将两个字节的DOS行尾"\r\n"转换为单个字节的UNIX行尾"\n"以实现预期的结果。

您应该能够通过将任何已注释的行中的"\n"替换为"\r"来完成此操作。


1
我忘了提到这个文件是从Windows写入Samba共享的,我完全忘记了我应该寻找\r而不是\n。我给你点赞并表示感谢! - Bogdan Constantinescu
1
谢谢您的见解。我正在__Linux__上使用csv模式从sqlite3生成输出,但输出似乎有\r\n终止符。在看到您的评论并意识到这是问题之前,我浪费了很多时间... - Tasos Papastylianou

14

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

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

如果您遇到回车符问题:tr -d '\r' <file |sh


当然可以,但那部分是我的批处理文件。它不仅仅是从文件执行简单的命令,因为如果只是这样的话,我肯定只会使用 sh - Bogdan Constantinescu

2
我尝试了以下内容:
read line
echo -n $line | od -x

针对输入的 'xxxx',我得到了如下结果:

0000000 7878 7878

如您所见,变量的内容末尾没有\n。建议使用选项-x运行脚本(bash -x script)。这将打印所有被执行的命令。
[编辑] 您的问题在于您在Windows上编辑了commands.txt文件。现在,该文件包含CRLF(0d0a)作为行分隔符,这使得read混淆(还有ls\r不是已知的命令)。使用dos2unix或类似工具将其转换为Unix文件即可。

问题是我不从键盘读取。我将我的 STDIN 更改为文件(上面的 command.txt),如果我在 '' 之间回显 $line,我会得到输出 'ls'。 - Bogdan Constantinescu
我在 echo -n $line | od -x 上得到的输出是 "0000000 736c 000d 0000003"。 - Bogdan Constantinescu
1
0d是回车符,不同于换行符。 - cms
啊!你在Windows上编辑了那个文件,现在它里面有CRs!使用dos2unix或类似的脚本将CRLF(0d0a)转换为LF(0a)。 - Aaron Digulla
+1,我知道更好的选择,但由于某些原因我使用了Windows。这对我帮助很大。谢谢。 - Dominic P

2
您可以尝试使用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' 

1

你需要使用 eval 命令


#!/bin/bash -x

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

我运行了以下命令:

./script.sh < file.txt

其中file.txt的内容如下:

ls
ls -l
ls -ltra
ps as

0
以下脚本可以正常工作(至少对我来说是这样的):
#!/bin/bash

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

0

虽然不能用于ls,但我建议看一下find-print0选项


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接