cp890 has asked for the wisdom of the Perl Monks concerning the following question:

My intent is to change the shell with inplace editing on a user or group of users by using variables thru substitution on different platforms- Linux, HPUX, Solaris,but I cannot get pass the script failure

I am focus on user1 in the script below but would also like to see a script example if I wanted to in place edit user1 and user3.

Input --temp_pass

user1:x:9760822:3241:USER 1:/home/user1:/bin/bash

user2:x:9760822:3242:USER 2:/home/user2:/bin/ksh

user3:x:9760822:3243:USER 3:/home/user3:/bin/sh

Output to achieve is:

user1:x:9760822:3241:USER 1:/home/user1:/bin/nologin

user2:x:9760822:3242:USER 2:/home/user2:/bin/ksh

user3:x:9760822:3243:USER 3:/home/user3:/bin/nologin

Script failure

perl -w test_replace.pl

Use of uninitialized value in substitution (s///) at test_replace.pl line 26.

Use of uninitialized value in print at test_replace.pl line 27.

#!/usr/bin/perl open (LOGFILE, '>> test_replace.txt'); $IN_PASS = 'temp_pass'; # File to be edited print LOGFILE "File being edited---$IN_PASS\n"; # local $^I = '.bak'; # Call for in-place editing; make backups with a +.bak suffix $ID = "user1"; # (@PW_LIST) = ('user1' , 'user3'); #print LOGFILE "@PW_LIST\n"; # #foreach ($ID) @PW_LIST { #Loop to change shell if file +s exists $HOME_DIR = `cat ${IN_PASS} | grep $ID| cut -d: -f6`; $L_ID = `cat ${IN_PASS} | grep $ID`; $L_USER = `cat ${IN_PASS} | grep $ID | cut -d: -f1-6`; print LOGFILE " $L_ID\n"; print LOGFILE " $L_USER\n"; print LOGFILE "Current home directoy for $ID:$HOME_DIR\n"; $GO_TEST1 = "test_file1"; $GO_TEST2 = "test_file2"; # if (( "($HOME_DIR)/($GO_TEST1)") && ("($HOME_DIR)/($GO_TEST2)")) { +# verifying both files exists $CURR_SHELL = `cat ${IN_PASS} | grep $ID| cut -d: -f7`; print LOGFILE "Current Shell for $ID: $CURR_SHELL\n"; $NEW_SHELL = "/bin/nologin"; print LOGFILE "Replacing shell for \"$ID\" with $NEW_SHELL.\n"; s?$L_ID?$L_USER:$NEW_SHELL?g; print; } else { print LOGFILE " FAILED: ($HOME_DIR)/($GO_TEST1) and/or ($HOME_DIR)/( +$GO_TEST2) is missing for ($ID).\n"; } print LOGFILE "Finished\n"; close LOGFILE;

Replies are listed 'Best First'.
Re: in place editing by variables
by hdb (Monsignor) on Apr 11, 2013 at 18:19 UTC

    I have not been sys admin for a UNIX box for a long time. To me it seems dangerous to edit the passwd file with a script like yours. As a minimum I would ask for "use strict;" in the script. Also, there is a number of modules on CPAN to edit the passwd file in a controlled manner, e.g. Unix::PasswdFile among others.

    If your aim is to learn how to do things yourself, then I would think that the passwd file is not the best object for that.

    UPDATE: Here is a sample script.

    my $pw = new Unix::PasswdFile "passwd"; # for real this should be /et +c/passwd or similar $pw->shell( "user1", "/bin/nologin" ); $pw->commit(".bak");
Re: in place editing by variables
by roboticus (Chancellor) on Apr 11, 2013 at 17:53 UTC

    cp890:

    Are you sure your script is actually failing? It may be doing everything correctly and also emitting those warning lines. Typically I see that sort of error because a blank line (such as the end) in a file has no information on it.

    For example:

    $ cat t.pl use strict; use warnings; while (<DATA>) { my @f = split /\s+/,$_; $f[1] =~ s/foo/bar/g; print "result: $f[1]\n"; } __DATA__ Poor foolish kitty The empty line above this one might fool us. $ perl t.pl $ perl t.pl result: kitty Use of uninitialized value $f[1] in substitution (s///) at t.pl line 6 +, <DATA> line 2. Use of uninitialized value $f[1] in concatenation (.) or string at t.p +l line 7, <DATA> line 2. result: result: barlish Use of uninitialized value $f[1] in substitution (s///) at t.pl line 6 +, <DATA> line 4. Use of uninitialized value $f[1] in concatenation (.) or string at t.p +l line 7, <DATA> line 4. result:

    A simple fix would be to ignore blank lines:

    while (<DATA>) { next if /^\s*$/; # skip blank lines ... }

    Update: Minor code edit. (Made first case actually substitute.)

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: in place editing by variables
by reisinge (Hermit) on Apr 11, 2013 at 18:54 UTC

    I agree with hdb that it's safer (and easier) to use modules. Also consider using usermod --shell <new_shell> system command, on Linux, at least.

    One way to replace the shell manually:

    use strict; use warnings; my $new_shell = "/bin/nologin"; # in-place editing with backup $^I = ".bak"; # diamond operator "<>" reads from command line arguments or STDIN while ( my $line = <> ) { # skip empty lines next if $line =~ /^\s*$/; # split on ":" and return the 7th field (list slice) my $old_shell = ( split ":", $line )[6]; $line =~ s/$old_shell/$new_shell/; print "$line\n"; }

    Update: using explicit variable $line instead of default variable $_ for better readability.

    Well done is better than well said. -- Benjamin Franklin

Re: in place editing by variables
by 2teez (Vicar) on Apr 11, 2013 at 19:13 UTC

    "...I am focus on user1 in the script below but would also like to see a script example if I wanted to in place edit user1 and user3..."

    I agree with hdb and others totally here, however, if you still want to practice with your originally Posted data as shown in your post. You can go through the line one by one substituting for user1 and user3 like so:

    use warnings; use strict; while(<DATA>){ chomp; if(/^user(1|3):/){ s{(?<=/bin)(.+?)$}{/nologin}; } print $_,$/; } __DATA__ user1:x:9760822:3241:USER 1:/home/user1:/bin/bash user2:x:9760822:3242:USER 2:/home/user2:/bin/ksh user3:x:9760822:3243:USER 3:/home/user3:/bin/sh
    Output:
    user1:x:9760822:3241:USER 1:/home/user1:/bin/nologin user2:x:9760822:3242:USER 2:/home/user2:/bin/ksh user3:x:9760822:3243:USER 3:/home/user3:/bin/nologin

    If you tell me, I'll forget.
    If you show me, I'll remember.
    if you involve me, I'll understand.
    --- Author unknown to me

      thanks for all your responses- I have at least one OS if a process is running - the usermod returns in use. I cant always bring down the app or db associated. some of servers i can use vipw which works, but is manual and subject to more errors and some servers and OS do not have vipw- this is why i going with the script and backup