shell script error in unix - shell

what does using 1# for a directory do here?
cpfile=${1#/usr/newconfig} ls -l $cpfile | read var1 echo var1
I am tryiing to understand the script, but I cannot find any resource that would help me ascertain the meaning of this command.

In general, variables can be modified with #, which removes a leading string. If a is a variable with content foobar, then ${a#foo} strips the foo and evaluates to bar. In your case, $1 is a positional parameter, and ${1#/usr/newconfig} is the value of that string with "/usr/newconfig" removed from the start. If it does not match, the expression evaluates to the same string as $1.
However, this script has a rather significant issue in that it assigns cpfile in the environment of the ls that is run, but ls does not receive it as an argument. As a result, ls is going to operate on the current working directory rather than the directory passed as an argument to the script. (unless cpfile is assigned previously in the script somewhere.)

Related

How can you use the actual regex value in an environment variable?

I'm writing a shell script for an assignment. The script is supposed to read regex argument and then use that regex. The problem is, if the user doesn't use single/double quotations then the regex will be evaluated before I need it to be evaluated.
Here's an example; let's say that the user executed the script and passed *f* as an argument, and the code has the following lines:
arg=$1 #*f*
echo "$arg"
In the above example echo returns a file name in the current directory that contains the regex *f*. I need echo to print *f*. It works if the user passes '*f*', but is there no other way?

how to filter a command subsitution from the resulting value of a readlink for symlink?

This may be poorly titled as I'm not fully sure what the process is called.
Basically I want to get only the last part of a symlink path, and I'm trying to use the same method I use with PWD.
For example:
if I do
PWD
it prints
/opt/ct/mydir
if I do
echo ${PWD##*/}
it prints only the last part
mydir
So using that design I can do
readlink mysymlink
which gives
/opt/ct/somedir
and I can do
TMP=$(readlink mysymlink)
echo ${TMP##*/}
and it will print
somedir
So now how can I combine that last part into one line like
TMP=$(readlink mysymlink && echo ${TMP##*/})
???
The example I show gives me 2 concatenated results.. one with the full path and one with just the part I want. I only want that last directory.
I also tried
TMP=${ $(readlink mysymlink)##*/}
to no avail
Variable substitution suffixes can only be used with variables, not command substitutions. You either have to set the variable and modify it in separate statements, as in your first attempt, or use additional command substitutions:
TMP=$(basename $(readlink))

Remove last argument from argument list of shell script (bash)

This question concerns a bash script that is run in automator osx. I am using automator actions to get and filter a bunch of file references from the finder. Then I append to that list the name of the parent folder, also via an automator action. Automator then feeds these arguments to an action called "run shell script". I am not sure exactly how automator invokes the script but the argument list looks like this when echoed with: echo "$#"
/Volumes/G-Raid/Online/WAV_TEST/Testbok 50/01/01000 43-001.wav /Volumes/G-Raid/Online/WAV_TEST/Testbok 50/02/02000 43-002.wav /Volumes/G-Raid/Online/WAV_TEST/Testbok 50/03/03000 43-003.wav /Volumes/G-Raid/Online/WAV_TEST/Testbok 50
In this case path to 3 files and a folder.
In the shell script I launch an application called ripcheckc* with the args passed from automator minus the last argument(the folder) in the list.
I use this to remove the last argument:
_args=( "$#" )
unset _args[${#_args[#]}-1]
And this is echo $_args:
/Volumes/G-Raid/Online/WAV_TEST/Testbok 50/01/01000 43-001.wav /Volumes/G-Raid/Online/WAV_TEST/Testbok 50/02/02000 43-002.wav /Volumes/G-Raid/Online/WAV_TEST/Testbok 50/03/03000 43-003.wav
Same as before but without the folder.
Now, if I run ripcheckc with "$#" as argument it works (but fails later on because of that last path in the argument list) If I use ${_args[#]} the application will just abort silently. When I echo $# and _args the output looks identical except for the last argument.
My question is - what is the difference between $# and $_args that make the first valid input and the second not?
*The application is ripcheckc
I hope my question makes sense.
EDIT: Solved.
I have used this bash one-liner before
set -- "${#:1:$(($#-1))}"
It sets the argument list to the current argument list, less the last argument.
How it works:
$# is the number of arguments
$((...)) is an arithmetic expression, so $(($#-1)) is one less than the number of arguments.
${variable:position:count} is a substring expression: it extracts count characters from variable starting at position. In the special case where variable is #, which means the argument list, it extracts count arguments from the list beginning at position. Here, position is 1 for the first argument and count is one less than the number of arguments worked out previously.
set -- arg1...argn sets the argument list to the given arguments
So the end result is that the argument list is replaced with a new list, where the new list is the original list except for the last argument.
Assuming that you already have an array, you can say:
unset "array[${#array[#]}-1]"
For example, if your script contains:
array=( "$#" )
unset "array[${#array[#]}-1]" # Removes last element -- also see: help unset
for i in "${array[#]}"; do
echo "$i"
done
invoking it with: bash scriptname foo bar baz produces:
foo
bar
You can also get all but the last argument with
"${#:0:$#}"
which, honestly, is a little sketchy, since it seems to be (ab)using the fact that arguments are numbered starting with 1, not 0.
Update: This only works due to a bug (fixed in 4.1.2 at the latest) in handling $#. It works in version 3.2.
set -- "${#:1:$#-1}"
sets the parameter list to first up to penultimate, removing the last one

Bash path issue

I have a script which contains the following line:
propFile="${0%/*}/anteater.properties"
What does "${0%/*}" mean?
This command gives a path to the script - but there is a spaces at path and script can't find this file - how to deal with it?
The % operator in variable expansion removes the matching suffix pattern given to it. So ${0%/*} takes the variable $0, and removes all matching /* at the end. This is equivalent to the command dirname, which, when given a path, returns the parent directory of that path.
In order to deal with spaces in bash variable, whenever expanding the variable (i.e. whenever you write $var), you should quote it. In short, always use "$var" instead of just $var.
Consider reading shell parameter expansion and variable quoting in the bash manual to learn more about these two subjects.
strips the suffix matching /*, i.e. everything after last slash including the slash itself.
quote it wherever you use it (cat "$propFile").

Bash script execute shell command with Bash variable as argument

I have one loop that creates a group of variables like DISK1, DISK2... where the number at the end of the variable name gets created by the loop and then loaded with a path to a device name. Now I want to use those variables in another loop to execute a shell command, but the variable doesn't give its contents to the shell command.
for (( counter=1 ; counter<=devcount ; counter++))
do
TEMP="\$DISK$counter"
# $TEMP should hold the variable name of the disk, which holds the device name
# TEMP was only for testing, but still has same problem as $DISK$counter
eval echo $TEMP #This echos correctly
STATD$counter=$(eval "smartctl -H -l error \$DISK$counter" | grep -v "5.41" | grep -v "Joe")
eval echo \$STATD$counter
done
Don't use eval ever, except maybe if there is no other way AND you really know what you are doing.
The STATD$counter=$(...) should give an error. That's not a valid assignment because the string "STATD$counter" is not a valid variable name. What will happen is (using a concrete example, if counter happened to be 3 and your pipeline in the $( ) output "output", bash will only expand that line as far as "STATD3=output" so it will try to find a command named "STATD3=output" and run it. Odds are this is not what you intended.
It sounds like everything you want to do can be accomplished with arrays instead. If you are not familiar with bash arrays take a look at Greg's Wiki, in particular this page or the bash man page to find out how to use them.
For example, in the loop you didn't post in your question: make disk (not DISK: don't use all upper case variable names) an array like so
disk+=( "new value" )
or even
disk[counter]="new value"
Then in the loop in your question, you can make statd an array as well and assign it with values from disk by
statd[counter]="... ${disk[counter]} ..."
It's worth saying again: avoid using eval.

Resources