Scripts in sed - linux - linux

I got the concept of bash, now, I found a site full of riddles for practising bash. I solve a couple of scripts (you should mention what do they do, what they are missing or so, depends on the question) and I bumped this script:
random_var="$(echo $1 | sed -e 's/[^[:alnum:]]//g')"
Correct me if I'm wrong about my basic assumptions on the following code:
$1 is the second argument that the script got (when the first is the script name)
There is a pipeline between the second argument and the sed script that removes all alpha numerics and... according to what I understand, this script can be "broken" by using a delimiter such as [/\]^$ and so ?
Now, there comes the difficulty (well, for me), the program gets an input from the user and, when the following script I just mention is found at a function returning true if the input is different than the result. I have no idea what is happening here, can someone enlighten me?
#!/bin/sh
func()
{
somevar="$(echo $1 | sed -e 's/[^[:alnum:]]//g')"
if [ "$somevar" != "$input" ] ; then
return 1
else
return 0
fi
}
# Sample usage of this function in a script
echo -n "Enter input: "
read input
if ! func "$input" ; then
echo "HELL NO"
exit 1
else
echo "YES!"
fi
exit 0

The script tests a string to see whether it contains any non-alphanumeric characters.
As Avinash has mentioned in the comments, the sed command removes all non-alphanumeric characters. Within the function, $input has the same value as it does in the calling scope, which is also the same as the first argument, $1. This is perhaps a little bit confusing...
If $somevar is different to $input (=$1), then this means that sed has changed the string in some way. Therefore, the string must contain at least one non-alphanumeric character.
If the function returns 1 (there were some non-alphanumeric characters in the input), then ! func is false, so the else branch will be executed and the script will return with an exit code of 0 (success). Otherwise, the script will return a non-zero exit code, indicating a failure.

Related

How to match substring with special characters in linux shell?

I wanted to check if a file contains a string in bash. I have done so for regular string characters. However, i need to check a new string which contains double quote ".
Say the string is:
PARAMETER_XYZ="no"
I tried this, but does not work:
ABC=$(cat /etc/file)
if [[ $ABC = *"PARAMETER_XYZ=\"no\""*]] ; then
exit 0
fi
Any suggestions?
grep is the program of choice to look for the presence of strings.
if grep 'PARAMETER_XYZ="no"' /etc/file > /dev/null then
exit 0
fi
You can also still do it with [[ if you really want:
ABC=$(cat /etc/file)
if [[ $ABC = *'PARAMETER_XYZ="no"'* ]] ; then
exit 0
fi
However, if that's actually a config file you're trying to parse, there are better solutions that are less fragile than looking for an exact string. That file looks like it might even be a shell variables file, in which case you could just source it and then check $PARAMETER_XYZ directly.

What would cause the BASH error "[: too many arguments" after taking measures for special characters in strings?

I'm writing a simple script to check some repositories updates and, if needed, I'm making new packages from these updates to install new versions of those programs it refers to (in Arch Linux). So I made some testing before executing the real script.
The problem is that I'm getting the error [: excessive number of arguments (but I think the proper translation would be [: too many arguments) from this piece of code:
# Won't work despite the double quoted $r
if [ "$r" == *"irt"* ]; then
echo "TEST"
fi
The code is fixed by adding double square brackets which I did thanks to this SO answer made by #user568458:
# Makes the code works
if [[ "$r" == *"irt"* ]]; then
echo "TEST"
fi
Note that $r is defined by:
# Double quotes should fix it, right? Those special characters/multi-lines
r="$(ls)"
Also note that everything is inside a loop and the loop progress with success. The problems occurs every time the if comparison matches, not printing the "TEST" issued, jumping straight to the next iteration of the loop (no problem: no code exists after this if).
My question is: why would the error happens every time the string matches? By my understanding, the double quotes would suffice to fix it. Also, If I count on double square brackets to fix it, some shells won't recognize it (refers to the answer mentioned above). What's the alternative?
Shell scripting seems a whole new programming paradigm.. I never quite grasp the details and fail to secure a great source for that.
The single bracket is a shell builtin, as opposed to the double bracket which is a shell keyword. The difference is that a builtin behaves like a command: word splitting, file pattern matching, etc. occur when the shell parses the command. If you have files that match the pattern *irt*, say file1irt.txt and file2irt.txt, then when the shell parses the command
[ "$r" = *irt* ]
it expands $r, matches all files matching the pattern *irt*, and eventually sees the command:
[ expansion_of_r = file1irt.txt file2irt.txt ]
which yields an error. No quotes can fix that. In fact, the single bracket form can't handle pattern matching at all.
On the other hand, the double brackets are not handled like commands; Bash will not perform any word splitting nor file pattern matching, so it really sees
[[ "expansion_of_r" = *irt* ]]
In this case, the right hand side is a pattern, so Bash tests whether the left hand side matches that pattern.
For a portable alternative, you can use:
case "$r" in
(*irt*) echo "TEST" ;;
esac
But now you have a horrible anti-pattern here. You're doing:
r=$(ls)
if [[ "$r" = *irt* ]]; then
echo "TEST"
fi
What I understand is that you want to know whether there are files matching the pattern *irt* in the current directory. A portable possibility is:
for f in *irt*; do
if [ -e "$f" ]; then
echo "TEST"
break
fi
done
Since you're checking for files with a certain file name, I'd suggest to use find explicitly. Something like
r="$(find . -name '*irt*' 2> /dev/null)"
if [ ! -z "$r" ]; then
echo "found: $r"
fi

Shell Script working with multiple files [duplicate]

This question already has answers here:
How to iterate over arguments in a Bash script
(9 answers)
Closed 5 years ago.
I have this code below:
#!/bin/bash
filename=$1
file_extension=$( echo $1 | cut -d. -f2 )
directory=${filename%.*}
if [[ -z $filename ]]; then
echo "You forgot to include the file name, like this:"
echo "./convert-pdf.sh my_document.pdf"
else
if [[ $file_extension = 'pdf' ]]; then
[[ ! -d $directory ]] && mkdir $directory
convert $filename -density 300 $directory/page_%04d.jpg
else
echo "ERROR! You must use ONLY PDF files!"
fi
fi
And it is working perfectly well!
I would like to create a script which I can do something like this: ./script.sh *.pdf
How can I do it? Using asterisk.
Thank you for your time!
Firstly realize that the shell will expand *.pdf to a list of arguments. This means that your shell script will never ever see the *. Instead it will get a list of arguments.
You can use a construction like the following:
#!/bin/bash
function convert() {
local filename=$1
# do your thing here
}
if (( $# < 1 )); then
# give your error message about missing arguments
fi
while (( $# > 0 )); do
convert "$1"
shift
done
What this does is first wrap your functionality in a function called convert. Then for the main code it first checks the number of arguments passed to the script, if this is less than 1 (i.e. none) you give the error that a filename should be passed. Then you go into a while loop which is executed as long as there are arguments remaining. The first argument you pass to the convert function which does what your script already does. Then the shift operation is performed, what this does is it throws away the first argument and then shifts all the remaining arguments "left" by one place, that is what was $2 now is $1, what was $3 now is $2, etc. By doing this in the while loop until the argument list is empty you go through all the arguments.
By the way, your initial assignments have a few issues:
you can't assume that the filename has an extension, your code could match a dot in some directory path instead.
your directory assignment seems to be splitting on . instead of /
your directory assignment will contain the filename if no absolute or relative path was given, i.e. only a bare filename
...
I think you should spend a bit more time on robustness
Wrap your code in a loop. That is, instead of:
filename=$1
: code goes here
use:
for filename in "$#"; do
: put your code here
done

Understanding and Clarification on AIX and Batch File

I am new to AIX and I have trouble understanding the codes stated in the shell script as shown below, I have a few questions.
if [ "$OutChlName" != "" ] ; then
echo START CHANNEL \($OutChlName\)
fi
For the first line, what does the "" mean, does it mean null?
\($OutChlName\) - is there any way to convert this to a batch file format.
Is it right to say that fi is the end tag of if?
Thank you.
The echo is only wanted when the variable OutChkName is filled.
The string is compared with an empty string.
When you read man test, you can find the alternative if [ -n "$OutChlName" ].
echo with double quotes
Within quotes you do not need the backslashes.
echo "START CHANNEL ($OutChlName)"
My echo behaves different when the OutChlName variable has special characters like newlines or *. I think my syntax is a slight bugfix, but when you do not want to change the original behaviour, you can use
echo "START CHANNEL ("$OutChlName")"
Using backslashes is also a valid syntax (batch format).
fi ends if
Also esac ends case, and done ends do (Odd, it should have been od).

comparison [ "$var" == "value" ] always false; how can this be debugged?

I'm having a ton of trouble with an if statement in bash. Here's what I have:
if [ "$returncode" == "HTTP/1.1 200 OK" ]; then
echo "Works!"
fi
This will not work successfully. I've verified over and over again that the variable $returncode is equal to the text specified, I'll print the two values right before this and they are definitely identical.
I've tried a couple different variations of this statement, all with no luck. I feel like a moron because this should be extremely simple! What do you think is wrong here?
If the values truly are identical (no hidden characters), the most likely problem is that your shell isn't actually bash.
/bin/sh only promises compliance with the POSIX sh standard, and == isn't a valid comparison operator in POSIX test; the standard-compliant string comparison operator is =.
Also try eliminating a CR from the end of the line:
#!/bin/bash
# ^^^^ NOT /bin/sh ($'...' is a non-POSIX extension)
# ...and if starting with an explicit interpreter, "bash yourscript", not "sh yourscript"
set -x # this will log each command run to stderr, allowing easy debugging
if [ "${returncode%$'\r'}" = "HTTP/1.1 200 OK" ]; then
echo "Works!"
fi
${foo%val} expands to the contents of $foo with any suffix consisting of val removed; $'\r' is, in bash, a constant referring to the ASCII CR character, which would be present if reading a CRLF-terminated string using standard UNIX tools (which expect LF-only newlines).

Resources