I am taking a intro to Unix class and am stuck on the final assignment. I need to write a script to change the file extension of a filename that is input when the script is run. The new file extension is also input when the script is run. The script is call chExt1.sh . Our first trial of the script is run as follows
./chExt1.sh cpp aardvark.CPP
The script is suppose to change the second input file extension to the file extension given in the first input. It is not suppose to matter what file extension is given with the file name or what file extension is given as the new extension, nor is it only for changing uppercase to lowercase. In hope to make this very clear if given the following:
./chExt1.sh istink helpme.plEaSe
The script would change helpme.plEaSe to helpme.istink . I have searched on this forum and in google and have had no look with trying the different examples I found. Below is some of the examples I have tried and what I currently have.
Current
#!/bin/sh
fileExtension="$1"
shift
oldName="$2"
shift
newName=${oldName%%.*}${fileExtension}
echo $newName
The echo is just to see if it works, and if I get it working I'm going to add an mv to save it.
Others that I have tried:
newName=`${oldName%.*}`
newName=`${oldName#.*}`
sed 's/\.*//' $oldName > $newName
I can't seem to find some of the other sed I have used but they involved alot of backslashes and () with .* in there. I did not try the basename command cause I don't know the file extension to be entered and all I the examples I saw required that you specify what you wanted removed and I can't. I did not list all the different quote variations that I used but I have tried alot. My instructions say to use the sed command since we should know how to use that from class but when I try to do it I don't isolate just the ending of the file and I believe (cause it takes so long to finish) that it is going through the whole file and looking for .'s and anything after cause I kept doing .* as the pattern. Thanks for anyhelp you can give.
shift shifts the positional parameters, so after calling shift the second parameter ($2) is now the first ($1). The second shift is not necessary, because you are done accessing the parameters. You need to either remove the shift
#!/bin/sh
fileExtension="$1"
oldName="$2"
newName=${oldName%%.*}${fileExtension}
echo $newName
or change $2 to $1.
#!/bin/sh
fileExtension="$1"
shift
oldName="$1"
newName=${oldName%%.*}${fileExtension}
echo $newName
However, you are still missing a dot from your new file name. That is left as an exercise for the reader.
Related
I want to change my PATH variable in zsh.
Problem: I don't understand where in the .zshrc file I have to make modifications.
Normally, I would look for the assignment to the PATH variable and set the values from scratch how I would like them to be (leaving all the systems binaries directories untouched).
The first lines in my .zshrc file are as follows:
# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:/usr/local/bin:$PATH
# Path to your oh-my-zsh installation.
export ZSH="/Users/Sam/oh-my-zsh"
export PATH=$PATH:/Applications/Postgres.app/Contents/Versions/13/bin
etc.
My actual PATH variable is:
/Library/Frameworks/Python.framework/Versions/3.9/bin:/Library/Frameworks/Python.framework/Versions/3.8/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Postgres.app/Contents/Versions/13/bin
I want to delete the directory where python3.8 is in, it's redundant.
My questions:
Do I have to change line 2 or line 7 in my .zshrc file?
Line 2 is commented out...is it executed anyway at the start of the terminal?
I have tried to comment out line 7. But the postgres directory still remained in my PATH variable which I don't understand.
The .zshrc is located in the home dir. The dot at the beginning keeps it hidden. Type ls -a from ~ directory to see it. To edit just run vim, nvim, etc as usual.
nvim ~/.zshrc
This is the command for Neovim. For your editor, sub nvim for the proper command.
Once you get in, you need only add the same export command that you would add from the command line.
export PATH=$PATH:/whatever/you/are/adding
EDIT
To remove a path variable:
First, run the command:
echo $PATH
from the command line.
Next, Copy the output to clipboard.
Finally, at the very end of the .zshrc file, add the following:
export PATH=<paste-what-you-copied-here>
Because you didn't reference $PATH after the =, this will set the path to EXACTLY what you pasted, no more, no less. Adding $PATH: as in the first example will just add whatever to the end of what is already there.
Since this gives you access to every item in the path array, deleting is just a matter of a literal highlight/select and of whatever you want deleted.
Finally, be sure that there is only one place in the file where you are editing PATH. If there are more than one, the result can be confusing to say the least.
That said, I believe the script runs top-to-bottom, so only the last mention should persist. You can take advantage of this in some situations, but for this purpose, one will suffice. XD
Be careful when you decide to fiddle with the PATH in .zshrc: Since the file is processed by every interactive subshell, the PATH would get longer and longer for each subshell, with the same directory occuring in it several times. This can become a nightmare if you later try to hunt down PATH-related errors.
Since you are using zsh, you can take advantage that the scalar variable PATH is mirrored in the array variable path, and that you can ask zsh to keep entries in arrays unique.
Hence, the first thing I would do is put a
typeset -aU path
in your .zshrc; this (due to mirroring) also keeps the entries in PATH unique. You can put this statement anywhere, but I have it for easier maintenance before my first assignment to PATH or path.
It is up to you to decide where exactly you add a new entry to PATH or path. The entries are searched in that order which is listed in the variable. You have to ask yourself two questions:
Are some directories located on a network share, where you can sometimes expect access delays (due to bad network conditions)? Those directories should better show up near the end of the path.
Do you have commands which occur in more than one directoryin your path? In this case, a path search will always find the first occurance only.
Finally, don't forget that your changes will be seen after zsh processes the file. Therefore, you could create a new subshell after having edited the file, or source .zshrc manually.
I want to write a bash script that takes a user input (which will be a filename) and replaces a path to a file inside a css file with that filename. For simplicity, the two files will be in the same folder and in the css code only the filename at the end of the path should be changed.
I thought of using regex to match any line of code that has a specific pattern and then change the end of it. I know about sed, but since the filename always changes I'm not sure how to solve this problem other than regex. I also thought of adding a variable in the css file that holds the filename as a value and then adding that variable at the end of the path, but I'm not sure then how to access that variable from a bash script.
Any recommendations on how to tackle this problem?
Thanks!
Edit Adding more Information:
Here is the line in the css file I want to edit. The part to be changed is the fileName.png at the end. Since it will change I thought of using a regex to "find" the correct spot in the css file.
background: #2c001e url(file:////usr/share/backgrounds/fileName.png/);
A regex matching only this line in this specific file is the following. It could probably be simplified, but I don't see a reason why since it should work too:)
(background)\:\s\#.{6}\s(url)\((file)\:\/{4}(usr)\/(share)\/backgrounds\/.+\.(png)\/\)\;
So, there are some ways to do that. You can check topic in links below. sed command is also good idea. But before executing it, you can build a new variable (or multiple variables) to use them in regex sed -e syntax.
Getting the last argument passed to a shell script
Maybe, if you will add some input and output examples, I could be more specific in this case.
To replace the input in the file at run-time you could use this line in a script
sed "s/stringToReplace/$1/g" templateFile >fileToUse
the $1 is referencing the 2nd bash script argument (the first being $0, the name of the invoking script). stringToReplace would be written in verbatim in the templateFile.
You could also use a script with two runtime arguments ($1, $2), and you would change the original contents of the fileToUse using the -i option. But this requires storage of the last file path to be used as argument $1.
To make recurring tasks easier, I like to code shell scripts which (mostly) perform them for me. One of my latest scripts is for creating ed2k links with included http download URLs.
One example of what I want to achieve: Given that I want to download a specified version of Notepad++ to my "Shared" folder, I just type:
./dl-notepadpp.sh 6.0.0
I made it to the point where it downloads all files and passes them to the alcc command; which, however, prints plain ed2k links without any references.
I basically need a piped sed command which turns the alcc output
ed2k://|file|npp.6.0.0.bin.7z|7631311|8b8298915a2670c3f11416ba95f78a88|/
into
ed2k://|file|npp.6.0.0.bin.7z|7631311|8b8298915a2670c3f11416ba95f78a88|s=http://download.tuxfamily.org/notepadplus/6.0.0/npp.6.0.0.bin.7z|/
automatically.
(Of course I don't just want N++ and not just one file, so, technically, I need a sed command to add "s=http..." with a file name from an earlier part of the line.)
I tried using $1 in the replacement string for sed which doesn't work.
Any clues?
I am using the maven plugin appassembler to generate a unix script. In its tag, I put sth like:
<commandLineArguments>
<commandLineArgument>$1</commandLineArgument>
<commandLineArgument>$2</commandLineArgument>
<commandLineArgument>$3</commandLineArgument>
</commandLineArguments>
The resultant script, however, shows
$1 $2 $3 "$#"
I don't know where the last one came from, it therefore repeat the first 3 arguments.
Mojo's AppAssembler Maven Plugin generates a script that always appends all the command line arguments provided to the script onto the JVM's launch command. Thus if you did nothing, the "$#" will be the last thing on the JVM command used to start the program.
The <commandLineArguments> tag is used to inject additional command line arguments before the ARGLIST matcher.
It seems (to me) that you think you needed to add the positional markers in order to get the parameters passed through, hence the snippet you were adding. That is both:
Unnecessary, as by default the plugin generates a script that passes all required parameters.
Actually a potential bug, as what you have configured does not handle argument quoting and escaping correctly.
With regard to the second point consider the case where the second parameter is the name of a file that contains a space charater. If I launch the script for you program like so
$ bin/foo.sh Document.txt Document\ 2.txt "Copy of Document 3.txt" Doc4.txt
you will actually see the following being passed through to your Java program with the configuration you provided:
Document.txt (all of $1)
Document ($2 is expanded, but not quoted so now gets re-evaluated)
2.txt
Copy ($3 is expanded, but not quoted, so also gets re-evaluated, spaces seen as argument separator again)
of
Document
3.txt
Document.txt (now the ARGLIST matcher provides everything correctly)
Document 2.txt
Copy of Document 3.txt
Doc4.txt
The solution is simple. Stop trying to configure something you don't need to configure!
#!/bin/bash
echo 'first line' >foo.xml
echo 'second line' >>foo.xml
I am a total newbie to shell scripting.
I am trying to run the above script in cygwin. I want to be able to write one line after the other to a new file.
However, when I execute the above script, I see the follwoing contents in foo.xml:
second line
The second time I run the script, I see in foo.xml:
second line
second line
and so on.
Also, I see the following error displayed at the command prompt after running the script:
: No such file or directory.xml
I will eventually be running this script on a unix box, I am just trying to develop it using cygwin. So I would appreciate it if you could point out if it is a cygwin oddity and if so, should I avoid trying to use cygwin for development of such scripts?
Thanks in advance.
Run dos2unix on your shell script. That will fix the problem.
I had the same kind of problem as the original poster: A very simple script file was not working in Cygwin.
Thanks to Don Branson for the clue.
The fix for me was built into the text editor I'm using. (Most programmer's editors have a feature like this.) For example, in my case I'm using Notepad++, which has a menu item to convert the file line endings to Unix-style. From the menu: [Edit]->[EOL Conversion]->[Unix (LF)]
Then the script behaved as expected.
But there must be something else that is wrong here. When I try it, it works as expected.
> foo.xml puts the line into foo.xml, replacing any previous contents.
>> foo.xml appends to file
It sounds like you may have a typo somewhere. Also keep in mind that while the Windows command prompt can be forgiving about paths with embedded spaces, cygwin's shells will not be, so if you have a filename that contains embedded spaces, you need to either quote the filename or escape the spaces:
echo 'first line' > 'My File.txt'
echo 'first line' > My\ File.txt
The same goes for certain "special" characters including quotes, ampersand (&), semicolons (;) and generally most punctuation other than period/full-stop (.).
So if you are seeing those issues using the exact script that you are running (i.e. you copy and pasted it, there is no possibility of transcription errors) then something truly strange may be happening that I can't explain. Otherwise, there may be a misplaced space or unquoted character somewhere.
I cannot reproduce your results. The script you quote looks correct, and indeed works as expected in my installation of Cygwin here, producing the file foo.xml containing the lines first line and second line; implying that what you are actually running differs from what you quoted in some way that is causing the problem.
The error message implies some sort of problem with the filename in the first echo line. Do you have some nonprintable characters in the script you are running? Have you missed escaping a space in the filename? Are you subsituting shell variables and mistyping the name of the variable or failing to escape the resulting string?
The above should work normally..
However you can always specify a heredoc:
#!/bin/bash
cat <<EOF > foo.xml
first line
second line
EOF