Trying to clone a ksh function with little modification with a one liner perl - perl

I've a short ksh script that is often generated automatically. However, it's missing some stuff and I want to be able to "fix it" like I want by running a simple 1 liner perl to sed it.
Let say that the ksh contains the following function:
foo()
{
/some/command param1
if [[ $? -eq 0 ]]
then
/some/other/command stop param1
fi
/some/command param2
if [[ $? -eq 0 ]]
then
/some/other/command stop param2
fi
#...
}
and what I really want looks like this
foo_force()
{
/some/command param1
if [[ $? -eq 0 ]]
then
/some/other/command stop -f param1
fi
/some/command param2
if [[ $? -eq 0 ]]
then
/some/other/command stop -f param2
fi
#...
}
foo()
{
/some/command param1
if [[ $? -eq 0 ]]
then
/some/other/command stop param1
fi
/some/command param2
if [[ $? -eq 0 ]]
then
/some/other/command stop param2
fi
#...
foo_force
}
So far I've been able to get something "close", ie 2 perl commands, which would be ok with me. However, the second command only replace the last stop by a -f stop... which is not what I'm looking for.
/usr/bin/perl -i -pe "BEGIN{undef $/;}; s/^(foo)(\(\)\n{.*\n)}/\1_force\2}\n\n\1\2\t\1_force\n}/gms" /tmp/foo.ksh
/usr/bin/perl -i -pe "BEGIN{undef $/;}; s/^(foo\(\)\n{.* stop)( .*\n})/\1 -f\2/gms" /tmp/foo.ksh

This might work for you (GNU sed):
sed -i '/^foo()/{:a;$!N;/\n}/!ba;h;s/^foo/&_force/;s/stop /&-f /g;s/$/\n/p;g;s/\n}/\n\n foo_force&/}' /file

Using perl
perl -0777 -i -pe '
s{(^foo\(\).*?\n\})}{
my $foo = my $force = $1;
$foo =~ s/\}$/ foo_force()\n\}/;
$force =~ s/^foo\K/_force/;
$force =~ s/ stop \K/-f /g;
"$foo\n$force"
}mse;
' /tmp/foo.ksh

Related

How do I fix 'command not found' that popped out when I tried 'egrep' from a variable?

I wanted to make a program that searches all the lines that contains all the factors given, from a file mydata. I tried to egrep first factor from mydata and save it in a variable a. Then, I tried to egrep the next factor from a and save the result to a again until I egrep all the factors. But when I executed the program, it said
"command not found" in line 14.
if [ $# -eq 0 ]
then
echo -e "Usage: phoneA searchfor [...searchfor]\n(You didn't tell me what you want to search for.)"
else
a=""
for i in $*
do
if [ -z "$a" ]
then
a=$(egrep "$i" mydata)
else
a=$("$a" | egrep "$i")
fi
done
awk -f display.awk "$a"
fi
I expected all the lines including all the factors outputted on the screen in the pattern that I made in display.awk.
$a contains data, not a command. You need to write that data to the pipe.
if [ $# -eq 0 ]
then
printf '%s\n' "Usage: phoneA searchfor [...searchfor]" "(You didn't tell me what you want to search for.)" >&2
exit 1
fi
a=""
for i in "$#"; do
if [ -z "$a" ]; then
a=$(egrep "$i" mydata)
else
a=$(printf '%s' "$a" | egrep "$i")
fi
done
awk -f display.awk "$a"

Check whether string starts with "!" in POSIX sh

Trying to create a condition based on whether the line starts with an "!".
Note: this is sh not bash
#!/bin/sh
if [ $line = "!*" ] ;
then
echo "$0: $line has !"
else
echo "$0: $line has no !"
fi
In POSIX test, = performs exact string comparisons only.
Use a case statement instead.
case $line in
"!"*) echo "$line starts with an exclamation mark" ;;
*) echo "$line does not start with an exclamation mark" ;;
esac
If you really want to put this in an if, you can do that:
if case $string in "!"*) true;; *) false;; esac; then
echo "$line starts with an exclamation mark"
else
echo "$line does not start with an exclamation mark"
fi
You can use the standard POSIX parameter substitution syntax.
${var#repl} will remove the repl from the beginning of the content of the $var variable.
So, you'll have:
$ var=test
$ echo ${var#t}
est
$ echo ${var#X}
test
So, in order to have a simple if statement to check if a variable starts with a string (! in your case), you can have:
#!/bin/sh
if test "$line" = "${line#!}"; then
echo "$0: $line has no !"
else
echo "$0: $line has !"
fi
PS: test ... is equivalent to [ ... ], so the above script is exactly the same as
#!/bin/sh
if [ "$line" = "${line#!}" ]; then
echo "$0: $line has no !"
else
echo "$0: $line has !"
fi
Could be as simple as echo "$STR" | cut -c -1.
#!/bin/sh
STR="!abcd"
if [ "!" = $(echo "$STR" | cut -c -1) ]; then
echo "true"
fi

Read variable further down in code in shell script

In a shell script I need to know the value of a variable further down in the code, without running through it first.
This pings $IP which is extracted from $VAR below the while loop.
The $VAR is unknown at the time this is extracted (IP=$(echo $VAR | awk '{print $1}'))
Is it possible to read VAR in before the while loop runs?
The code:
#!/bin/sh
TIMEOUT=10
IP=$(echo $VAR | awk '{print $1}')
while [ $TIMEOUT -ne 0 ];do
ping -c 1 -W 1 "$IP" >/dev/null
rc=$?
if [ $rc -eq 0 ];then
TIMEOUT=0
else
TIMEOUT=$(($TIMEOUT - 1))
echo $TIMEOUT
sleep 1
fi
done
# rest of code to run after while loop
VAR="192.168.0.1 t,r 20,e"

Resolve name by inode in current direcory

How can I resolve the name by the given inode in the current directory in the following script that prints all filenames of symlinks pointing to a specified file that is passed as an argument to the script. The list should be sorted by ctime.
#!/usr/bin/ksh
IFS="`printf '\n\t'`"
USAGE="usage: symlink.sh <file>"
get_ctime() {
perl -se 'use File::stat; $file=lstat($filename); print $file->ctime' -- -filename="$1"
}
stat_inode() {
perl -se 'use File::stat; $file=stat($filename); if (defined $file) { print $file->ino; }' -- -filename="$1"
}
lstat_inode() {
perl -se 'use File::stat; $file=lstat($filename); if (defined $file) { print $file->ino; }' -- -filename="$1"
}
if [ $# -eq 0 ]; then
echo "$USAGE"
exit 1
fi
FILE_NAME="$1"
FILE_INODE=$(stat_inode "$FILE_NAME")
if [ ! -e "$FILE_NAME" ]; then
echo "no such file \"$FILE_NAME\""
exit 1
fi
for LINK in ./* ./.[!.]* ;do
if [ -L "$LINK" ]; then
TARGET_INODE=$(stat_inode "$LINK")
if [ ! -z "$TARGET_INODE" ]; then
if [ "$FILE_INODE" -eq "$TARGET_INODE" ]; then
echo $(get_ctime "$LINK") $(lstat_inode "$LINK");
fi
fi
fi
done | sort -nk1 | awk '{print $2}'
Basically, I'd like to pipe awk to some kind of lookup function like this: | awk ' ' | lookup
I'd really appreciate if someone suggested a more elegant way to accomplish the task.
OS: SunOS 5.10
Shell: KSH
Something like this?
$ find . -maxdepth 1 -inum 2883399
./.jshintrc
$
or:
$ echo 2883399 | xargs -IX find . -maxdepth 1 -inum X
./.jshintrc
$

boolean expression in sh script

I have this simple script, which wouldn't run because of the line with if [ ... ]
Could anyone tell me what is wrong with this?
#! /bin/sh
if [ $# -ne 2 AND $# -ne 3 ]
then
echo "Usage $0 <input> <output> [<comment>]"
exit 1
fi;
Thanks!
Try the following :
#! /bin/sh
if [ $# -ne 2 -a $# -ne 3 ]
then
echo >&2 "Usage $0 <input> <output> [<comment>]"
exit 1
fi
Or :
#! /bin/sh
if [ $# -ne 2 ] && [ $# -ne 3 ]
then
echo >&2 "Usage $0 <input> <output> [<comment>]"
exit 1
fi
If you'd like to use bash :
#! /bin/bash
if [[ $# -ne 2 && $# -ne 3 ]]
then
echo >&2 "Usage $0 <input> <output> [<comment>]"
exit 1
fi