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

评论说你有我在问之前尝试过的东西。有什么解决办法吗?在过去的几个小时里,我一直在为此绞尽脑汁……

4

7 回答 7

18

我一直喜欢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.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”来做到这一点。

于 2009-09-22T10:30:43.713 回答
14

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

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

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

于 2009-09-22T12:15:54.077 回答
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 文件。

于 2009-09-22T10:28:50.373 回答
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' 
于 2009-09-22T15:45:53.053 回答
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为
于 2009-09-22T10:58:14.993 回答
0

虽然不适合ls,但我建议看看find's -print0option

于 2009-09-22T10:26:47.367 回答
0

以下脚本有效(至少对我而言):

#!/bin/bash

while read I ; do if [ "$I" ] ; then $I ; fi ; done ;
于 2009-09-22T11:05:35.760 回答