我遇到了以下问题:我正在编写一个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之前,我已经尝试了一些事情。有解决方案吗在过去的几个小时里,我正在粉碎我的大脑...
答案 0 :(得分:17)
我总是喜欢perl -ne 'chomp and print'
,用于修剪换行符。很好,很容易记住。
e.g。 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格式吗?如果是这样,那么你需要将结束“\ r \ n”的2字节DOS行转换为单字节UNIX 1,“\ n”以实现预期的结果。
您应该可以通过在任何注释掉的行中交换“\ n”来表示“\ n”。
答案 1 :(得分:12)
有人已经写了一个执行shell命令的程序:sh file
如果您真的只想执行文件的第一行:head -n 1 file |sh
如果您的问题是回车:tr -d '\r' <file |sh
答案 2 :(得分: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文件。
答案 3 :(得分:2)
您也可以尝试仅使用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'
答案 4 :(得分:1)
你需要eval命令
#!/bin/bash -x
while read cmd
do
if [ "$cmd" ]
then
eval "$cmd"
fi
done
我按原样跑了
./script.sh&lt; file.txt
file.txt是:
ls ls -l ls -ltra ps as
答案 5 :(得分:0)
虽然不适用于ls
,但我建议您查看find
的-print0
选项
答案 6 :(得分:0)
以下脚本有效(至少对我而言):
#!/bin/bash
while read I ; do if [ "$I" ] ; then $I ; fi ; done ;