如何使用命令行参数从bash运行perl脚本?

5

我正在尝试创建一个脚本来批量将一组用户标记为RT中的特权用户。我在RT wiki上找到了一个脚本,用于将用户添加到一个组并赋予他们特权状态,然后删除了与添加到组有关的部分。我剩下的perl脚本是:

#!/usr/bin/perl
# Usage: ./rt_set_privileged.pl <username>

use strict;
use lib "/var/www/ticket.ourcompany.com/lib";
use RT;
use RT::User;
use RT::Interface::CLI;

RT::LoadConfig();
RT::Init();

# Create RT User Object
my $user = new RT::User($RT::SystemUser);

# Instantiate the user object with the user passed as parameter
my $usertoadd = $ARGV[0];
$user->Load( $usertoadd );

# Set the privileged flag (1=privileged, 0=unprivileged)
$user->SetPrivileged(1);

exit 1

我有一个文件,里面每行都是一个用户名。 因为我还不会perl,所以我尝试编写了一个简单的bash脚本,通过循环遍历文件,并针对每个用户名运行一次perl脚本。目前这个Bash脚本的代码如下:

#!/bin/bash

touch commands.sh
cat usernames.txt | while read LINE ; do
        N=$((N+1))
        echo /home/chris/RT/bin/rt_set_privileged.pl \"$LINE\" >> commands.sh
        /home/chris/RT/bin/rt_set_privileged.pl \"$LINE\"
        perl /home/chris/RT/bin/rt_set_privileged.pl \"$LINE\"
        perl -w /home/chris/RT/bin/rt_set_privileged.pl \"$LINE\"
        eval /home/chris/RT/bin/rt_set_privileged.pl \"$LINE\"
        perl "/home/chris/RT/bin/rt_set_privileged.pl $LINE"
done
echo "Processed $N users"

您可以看到,我尝试了很多方法来运行命令,但都没有成功。令人烦恼的是,我可以在之后从commands.sh文件中取出任何命令并直接粘贴到终端中,这样可以正常工作。但是当它们通过bash脚本运行时,我只会收到一堆这样的消息:

[Tue Sep  4 07:43:56 2012] [critical]: _AddMember called with a parameter that's not an integer. (/var/www/ticket.ourcompany.com/lib/RT/Group.pm:912)
[Tue Sep  4 07:43:58 2012] [warning]: Use of uninitialized value $principal in pattern match (m//) at /var/www/ticket.ourcompany.com/lib/RT/Group.pm line 970. (/var/www/ticket.ourcompany.com/lib/RT/Group.pm:968)
[Tue Sep  4 07:43:58 2012] [error]: Group::HasMember was called with an argument that isn't an RT::Principal or id. It's (undefined) (/var/www/ticket.ourcompany.com/lib/RT/Group.pm:973)
[Tue Sep  4 07:43:58 2012] [warning]: Use of uninitialized value $principal in pattern match (m//) at /var/www/ticket.ourcompany.com/lib/RT/Group.pm line 970. (/var/www/ticket.ourcompany.com/lib/RT/Group.pm:968)
[Tue Sep  4 07:43:58 2012] [error]: Group::HasMember was called with an argument that isn't an RT::Principal or id. It's (undefined) (/var/www/ticket.ourcompany.com/lib/RT/Group.pm:973)
[Tue Sep  4 07:43:58 2012] [warning]: Use of uninitialized value in concatenation (.) or string at /var/www/ticket.ourcompany.com/lib/RT/User.pm line 341. (/var/www/ticket.ourcompany.com/lib/RT/User.pm:341)
[Tue Sep  4 07:43:58 2012] [critical]: User  is neither privileged nor unprivileged. something is drastically wrong. (/var/www/ticket.ourcompany.com/lib/RT/User.pm:341)
[Tue Sep  4 07:43:58 2012] [warning]: Use of uninitialized value $new_member in pattern match (m//) at /var/www/ticket.ourcompany.com/lib/RT/Group.pm line 911. (/var/www/ticket.ourcompany.com/lib/RT/Group.pm:911)

提示该命令在没有任何参数的情况下被运行。在这一点上,我实际上已经花费了解决它的时间来为每个用户运行一次命令,有人可以帮忙吗?


这里有一些有趣的事情,我尝试在 perl 脚本中添加 print "arg=<<$ARGV[0]>>\n"; 来查看传递了什么。我一直以为参数没有到达 perl 脚本中,但似乎实际上是到达了。在开头加上这个之后,我的输出就是: >>g=<<3Cubed 不,那不是拼写错误,打印结果只是看起来很奇怪。所以,参数已经传递给脚本了……我不明白。如果我将 /home/chris/RT/bin/rt_set_privileged.pl ChrisO 粘贴到终端中,则正常工作。但如果我将它粘贴到 bash 脚本中并运行它,则出现此问题。 - Chris O'Kelly
你能否尝试在print语句中不使用<< >>来打印ARGV[0]?实际上,我会编写一个程序来完成两件事情,首先打印传递的参数数量(scalar(@ARGV)),然后打印$ARGV[0]。像你为此编写的bash脚本一样从一个bash脚本中调用该程序,看看你得到了什么。 - Scooter
1
这是字符串编码!我会在另一个答案中发布它。 - Chris O'Kelly
@reinierpost 当我无法找出我的参数为何未被传递时,我开始这样做。在这种情况下,我知道文件中永远不会有空格,每行将只有一个单词,我希望将其用作单个参数。 - Chris O'Kelly
1
@Chris O'Kelly:为每个用户调用Perl脚本的更简单方法是xargs -n1 rt_set_privileged.pl < usernames.txt - reinierpost
显示剩余3条评论
5个回答

2
你的Perl代码中有很多编程错误——你得到的错误信息全都是编译器消息。因此,调用是正确的,但Perl代码是错误的。
你需要编辑Perl代码,直到所有的错误消息和警告消失。
编辑:在运行环境中,Perl代码是错误的。

嗨,但是如果我直接从终端运行脚本,即输入/home/chris/RT/bin/rt_set_privileged.pl ChrisO并运行它,它就可以正常工作,因此perl脚本必须是有效的。错误消息似乎表明(至少对我来说)一个预期的参数未定义,这支持了我的原始理论,即命令行参数没有全部传递,但现在我不确定了。 - Chris O'Kelly
好的 - 让我们举个例子,比如这个警告:[warning]: Use of uninitialized value $principal in pattern match (m//) at /var/www/ticket.minecorp.com/lib/RT/Group.pm line 970 -> 它表明在 Group.pm 模块中,变量 $principal 是空的,但不应该是空的。因此,在 Group.pm 的 API 使用中可能存在错误 - 前往 Group.pm 并查看它期望什么! - cslotty
RT库可能需要更多的参数/选项/函数调用或其他内容,以便执行您期望的操作 - 在这种情况下,您与缺少的参数的关系可能是正确的。 - cslotty
好的 - 还有另外一种可能性:如果两个不同的调用行为不同,那么可能是由于环境造成的(这是脚本编程中常见的陷阱)- 你说直接调用可以工作,但从bash脚本调用就不能工作? 那么这两个环境有什么区别呢? - cslotty
我不明白你的意思... 就我所看到的,错误提示表明$principle的值是从另一个函数的输出设置的,而那个函数失败了。在我的看来,$User变量的实例化失败了,这里的错误消息就从那里展开了。我无法理解这如何与使用API有关,因为我可以从相同的目录中运行此脚本,使用相同的命令行参数(就我所知),并使其成功运行。 - Chris O'Kelly
显示剩余3条评论

2

哎呀,我很遗憾意识到这个简单问题竟然花费了我这么长时间。

问题出在字符串格式化上-文件usernames.txt是由使用windows的人创建的,它具有dos格式(CRLF)。 我猜测参数是以[username] [LF]的形式到达,并破坏了$User变量的实例化。

我确定如果没有来这里讨论,我永远不会得到答案。我只是一直在自己试着解决,结果陷入了死循环。

解决方法很简单:

sudo apt-get install tofrodos
sudo fromdos usernames.txt

然后原始脚本起作用了。

非常感谢大家的帮助。

编辑:现在已经过了足够的时间,我将这个编辑从原始问题移动到它自己的答案中。


1
perl /home/chris/RT/bin/rt_set_privileged.pl "$LINE"

如果该文件已被设置为可执行文件,您也可以执行以下操作:
/home/chris/RT/bin/rt_set_privileged.pl "$LINE"

例如,
$ cat usernames.txt 
ikegami
Chris O'Kelly

$ cat script.pl 
#!/usr/bin/env perl
print "arg=<<$ARGV[0]>>\n";

$ while read LINE ; do script.pl "$LINE"; done <usernames.txt
arg=<<ikegami>>
arg=<<Chris O'Kelly>>

您可以使用xargs代替while read

$ xargs -n1 -d\\n script.pl <usernames.txt 
arg=<<ikegami>>
arg=<<Chris O'Kelly>>

嗨,这两个脚本都是可执行的,我已经在我的bash脚本中尝试了这两行代码。我得到了相同的错误信息。 - Chris O'Kelly
@Chris O'Kelly,那么你在其他地方肯定还有错误。你问如何传递参数,我回答了你的问题。 - ikegami
你说得对,你的回答确实恰当地解决了我的问题标题,因此你得到了我的点赞 :) - Chris O'Kelly
你的问题不仅仅是标题,而是表明你不知道如何解决它。实际上,这是你提供任何有用信息的唯一问题。如果你的脚本还有其他问题,请提出一个新问题,并提供一个最小化、可运行的演示来说明问题。 - ikegami
1
我不确定敌意来自何处,我只是问了一个问题,感谢你的回答,但你似乎更感兴趣争论我的问题。如果你读完整个帖子,你会发现我已经解决了我遇到的问题并发布了自己的解决方案,所以我不知道你所指的“进一步的问题”是什么,但就可运行的问题演示而言,你没有注意到我在问题中包含的完整脚本吗? - Chris O'Kelly
什么敌对情况???我已经告诉你如何继续,现在你的第一个问题已经回答了。 - ikegami

1
另一个解决方案:不要使用bash脚本,而是直接编辑perl脚本,打开您的usernames.txt文件并逐行读取 - 这也将解决您的问题。
就像这里http://www.perlfect.com/articles/perlfile.shtml所示:
my $file = "usernames.txt";
open USERS, "<$file" or die "Can't open $file ($!)";

while(<USERS>) {
 my $usertoadd = $_;
 chomp $usertoadd;
 $user->Load( $usertoadd );
 $user->SetPrivileged(1);
}

是的,这可能是更好的解决方案。但学习Perl是下周的任务。 - Chris O'Kelly

0
更新: 现在考虑到用户名中可能包含空格的情况,感谢Peniwize's Blog提供的宝贵提示。
OLD_IFS=$IFS
IFS=$'\n'    
priveleged=( $( cat usernames.txt) )
for i in "${priveleged[@]}"
do
    perl /home/chris/RT/bin/rt_set_privileged.pl $i
done
IFS=$OLD_IFS

我刚刚尝试了一下,但是我收到了同样的错误信息。奇怪的是-用户名中没有空格。其中有几个用户名中带有$,我可以理解会引起一些问题,但即使我从文件中删除这些用户名,只剩下字母用户名,问题仍然存在。 - Chris O'Kelly
@ChrisO'Kelly 奇怪。如果你用调用 perl 的那行代码替换成 echo $i,它应该会显示出你文件中所有的名字列表。 - David
我使用一个使用命令行参数的 Perl 脚本进行了测试,看起来它可以工作。 - David
@ikegami 更新的解决方案已经考虑到了空格。 - David

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