It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I haven't got Linux on my computer at the moment, so I was wondering if someone can test this code I wrote.
It is supposed to rename a file extension when you type something like this, to run it, into the terminal:
chaxxx zzz yyy *.zzz
"chaxxx" being the name of the file.
Here's the code I wrote:
>>deleted<<
Use an online compiler & interpreter for your tests. ideone supports Bash Script too.
EDIT:
It does work. ren.sh is your script name, here you go:
$ ls
asdf.doc ren.sh text.txt
$ ./ren.sh txt doc *.txt
text.txt
text
$ ls
asdf.doc ren.sh text.doc
Have you looked at the rename command? You are pretty much reinventing the wheel here.
From man rename
rename .htm .html *.htm
will fix the extension of your html files.
Edit
If you are going to do it yourself in bash then I would suggest the following code instead. Here are its benefits:
It handles files with spaces in
their names
It checks to see if the file it's about to modify actually
ends in the extension you want to
change before it attempts to mv
it.
It uses native Parameter Expansion syntax rather than call the external binary basename
It checks to see if the # of input parameters is at least 3, otherwise it echos a usage message and exits
It uses a for-loop with indirection rather than calling the test with shift
#!/bin/bash
if (( $# < 3 )); then
echo "Usage: $0 oldExt newExt files"
exit
fi
EXTf=$1
EXTt=$2
for (( i = 3; i <= $#; i++)); do
NAME=${!i}
if [[ "${NAME##*.}" == "$EXTf" ]]; then
mv "$NAME" "${NAME%.*}.$EXTt"
fi
done
Related
I currently working as a intern at a hosting firm. They asked me to write a bin/bash script to help automate a process to check the user's domain's and .pointers for them. And validate with a "whois" command if the domains/pointers are on our server's.
I'm new with bin/bash scripting but i was told i should check nested loops out. So to test my script out i made similar paths as they would look like on the server. /usr/local/directadmin/data/users/#USER#/domains.list and users/#USER#/domains/#DOMAIN NAME OF USER#.pointers
#part 1
for i in $(cat /home/MrC/Desktop/Users) #<the list of users i need to check)
do
if [ -f "/usr/local/directadmin/data/users/$i/domainlist.txt" ]
then
echo "/usr/local/directadmin/data/users/$i" >> /home/MrC/Desktop/output.tx$
cat "/usr/local/directadmin/data/users/$i/domainlist.txt" >> /home/carlos/Des$
fi
#part 2
for s in $(cat /home/mrC/Desktop/output.txt)
do
if [ -f "/usr/local/directadmin/data/users/$i/domains/$s.pointers" ]
then
echo "/usr/local/directadmin/data/users/$i" >> /home/MrC/Desktop/pointers.$
cat "usr/local/directadmin/data/users/$i/domains/$s.pointers" >> /home/MrC$
fi
done
done
So part 1 works this is the output.txt below
/usr/local/directadmin/data/users/testuser
lolla.nl
blaat2.nl
blaat3.nl
google2.nl
/usr/local/directadmin/data/users/testusers
blaat.nl
google.com
test.nl
pietje.nl
But i cant seem part two to work (no pointer file). my goal with part two of the script is to read the output (domainname) and put it #/$i/domains/$s.pointers.
I'm new on the forum i hope i asked my question in a proper fashion. if some one could give me hints/tips to which direction i should look that would be highly appreciated.
For
Do
if
then
for
do
COMMAND A
COMMAND B
COMMAND C
done
fi
done
while read -r i; do #stuff; done < /home/MrC/Desktop/Users (adjust IFS or specify the delimiter with the -d option to read).
– David C. Rankin
This question already has answers here:
Read user input inside a loop
(6 answers)
Closed 5 years ago.
First post here! I really need help on this one, I looked the issue on google, but can't manage to find an useful answer for me. So here's the problem.
I'm having fun coding some like of a framework in bash. Everyone can create their own module and add it to the framework. BUT. To know what arguments the script require, I created an "args.conf" file that must be in every module, that kinda looks like this:
LHOST;true;The IP the remote payload will connect to.
LPORT;true;The port the remote payload will connect to.
The first column is the argument name, the second defines if it's required or not, the third is the description. Anyway, long story short, the framework is supposed to read the args.conf file line by line to ask the user a value for every argument. Here's the piece of code:
info "Reading module $name argument list..."
while read line; do
echo $line > line.tmp
arg=`cut -d ";" -f 1 line.tmp`
requ=`cut -d ";" -f 2 line.tmp`
if [ $requ = "true" ]; then
echo "[This argument is required]"
else
echo "[This argument isn't required, leave a blank space if you don't wan't to use it]"
fi
read -p " $arg=" answer
echo $answer >> arglist.tmp
done < modules/$name/args.conf
tr '\n' ' ' < arglist.tmp > argline.tmp
argline=`cat argline.tmp`
info "Launching module $name..."
cd modules/$name
$interpreter $file $argline
cd ../..
rm arglist.tmp
rm argline.tmp
rm line.tmp
succes "Module $name execution completed."
As you can see, it's supposed to ask the user a value for every argument... But:
1) The read command seems to not be executing. It just skips it, and the argument has no value
2) Despite the fact that the args.conf file contains 3 lines, the loops seems to be executing just a single time. All I see on the screen is "[This argument is required]" just one time, and the module justs launch (and crashes because it has not the required arguments...).
Really don't know what to do, here... I hope someone here have an answer ^^'.
Thanks in advance!
(and sorry for eventual mistakes, I'm french)
Alpha.
As #that other guy pointed out in a comment, the problem is that all of the read commands in the loop are reading from the args.conf file, not the user. The way I'd handle this is by redirecting the conf file over a different file descriptor than stdin (fd #0); I like to use fd #3 for this:
while read -u3 line; do
...
done 3< modules/$name/args.conf
(Note: if your shell's read command doesn't understand the -u option, use read line <&3 instead.)
There are a number of other things in this script I'd recommend against:
Variable references without double-quotes around them, e.g. echo $line instead of echo "$line", and < modules/$name/args.conf instead of < "modules/$name/args.conf". Unquoted variable references get split into words (if they contain whitespace) and any wildcards that happen to match filenames will get replaced by a list of matching files. This can cause really weird and intermittent bugs. Unfortunately, your use of $argline depends on word splitting to separate multiple arguments; if you're using bash (not a generic POSIX shell) you can use arrays instead; I'll get to that.
You're using relative file paths everywhere, and cding in the script. This tends to be fragile and confusing, since file paths are different at different places in the script, and any relative paths passed in by the user will become invalid the first time the script cds somewhere else. Worse, you aren't checking for errors when you cd, so if any cd fails for any reason, then entire rest of the script will run in the wrong place and fail bizarrely. You'd be far better off figuring out where your system's root directory is (as an absolute path), then referencing everything from it (e.g. < "$module_root/modules/$name/args.conf").
Actually, you're not checking for errors anywhere. It's generally a good idea, when writing any sort of program, to try to think of what can go wrong and how your program should respond (and also to expect that things you didn't think of will also go wrong). Some people like to use set -e to make their scripts exit if any simple command fails, but this doesn't always do what you'd expect. I prefer to explicitly test the exit status of the commands in my script, with something like:
command1 || {
echo 'command1 failed!' >&2
exit 1
}
if command2; then
echo 'command2 succeeded!' >&2
else
echo 'command2 failed!' >&2
exit 1
fi
You're creating temp files in the current directory, which risks random conflicts (with other runs of the script at the same time, any files that happen to have names you're using, etc). It's better to create a temp directory at the beginning, then store everything in it (again, by absolute path):
module_tmp="$(mktemp -dt module-system)" || {
echo "Error creating temp directory" >&2
exit 1
}
...
echo "$answer" >> "$module_tmp/arglist.tmp"
(BTW, note that I'm using $() instead of backticks. They're easier to read, and don't have some subtle syntactic oddities that backticks have. I recommend switching.)
Speaking of which, you're overusing temp files; a lot of what you're doing with can be done just fine with shell variables and built-in shell features. For example, rather than reading line from the config file, then storing them in a temp file and using cut to split them into fields, you can simply echo to cut:
arg="$(echo "$line" | cut -d ";" -f 1)"
...or better yet, use read's built-in ability to split fields based on whatever IFS is set to:
while IFS=";" read -u3 arg requ description; do
(Note that since the assignment to IFS is a prefix to the read command, it only affects that one command; changing IFS globally can have weird effects, and should be avoided whenever possible.)
Similarly, storing the argument list in a file, converting newlines to spaces into another file, then reading that file... you can skip any or all of these steps. If you're using bash, store the arg list in an array:
arglist=()
while ...
arglist+=("$answer") # or ("#arg=$answer")? Not sure of your syntax.
done ...
"$module_root/modules/$name/$interpreter" "$file" "${arglist[#]}"
(That messy syntax, with the double-quotes, curly braces, square brackets, and at-sign, is the generally correct way to expand an array in bash).
If you can't count on bash extensions like arrays, you can at least do it the old messy way with a plain variable:
arglist=""
while ...
arglist="$arglist $answer" # or "$arglist $arg=$answer"? Not sure of your syntax.
done ...
"$module_root/modules/$name/$interpreter" "$file" $arglist
... but this runs the risk of arguments being word-split and/or expanded to lists of files.
I am using a bash script to execute a program. The program must take the following argument. (The program is gnuplot.)
gnuplot -e "filename='output_0.csv'" 'plot.p'
I need to be able to assemble the following string: "filename='output_0.csv'"
My plan is to assemble the string STRING=filename='output_0.csv' and then do the following: gnuplot -r "$STRING" 'plot.p'. Note I left the words STRING without stackoverflow syntax style highlighting to emphasise the string I want to produce.
I'm not particularly proficient at bash, and so I have no idea how to do this.
I think that strings can be concatenated by using STRING="$STRING"stuff to append to string? I think that may be required?
As an extra layer of complication the value 0 is actually an integer which should increment by 1 each time the program is run. (Done by a for loop.) If I have n=1 in my program, how can I replace the 0 in the string by the "string value" or text version of the integer n?
A safest way to append something to an existing string would be to include squiggly brackets and quotes:
STRING="something"
STRING="${STRING}else"
You can create the "dynamic" portion of your command line with something like this:
somevalue=0
STRING="filename='output_${somevalue}.csv'"
There are other tools like printf which can handle more complex formatting.
somevalue=1
fmt="filename='output_%s.csv'"
STRING="$(printf "$fmt" "$somevalue")"
Regarding your "extra layer of complication", I gather that this increment has to happen in such a way as to store the value somewhere outside the program, or you'd be able to use a for loop to handle things. You can use temporary files for this:
#!/usr/bin/env bash
# Specify our counter file
counter=/tmp/my_counter
# If it doesn't exist, "prime" it with zero
if [ ! -f "$counter" ]; then
echo "0" > $counter
fi
# And if it STILL doesn't exist, fail.
if [ ! -f "$counter" ]; then
echo "ERROR: can't create counter." >&2
fi
# Read the last value...
read value < "$counter"
# and set up our string, per your question.
STRING="$(printf "filename='output_%d.csv'" "${value}")"
# Last, run your command, and if it succeeds, update the stored counter.
gnuplot -e "$STRING" 'plot.p' && echo "$((value + 1))" > $counter
As always, there's more than one way to solve this problem. With luck, this will give you a head start on your reading of the bash man page and other StackOverflow questions which will help you learn what you need!
An answer was posted, which I thought I had accepted already, but for some reason it has been deleted, possibly because it didn't quite answer the question.
I posted another similar question, and the answer to that helped me also answer this question. You can find said question and answer here: bash: Execute a string as a command
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
Shell script to accept two parameters , i had a script file named createproject.sh
#!/bin/bash
echo "Project Name :$1 "
echo "Group Id : $2 "
mvn archetype:generate -DgroupId=$2 -DartifactId=$1 -DarchetypeArtifactId=maven- archetype-quickstart -DinteractiveMode=false
cd $1
mvn eclipse:eclipse -Dwtpversion=2.0
and i had to execute this by command
sh createproject.sh projectname com.test.app
where projectname and com.test.app are requires project name and package structure but i need to do something like
sh createproject.sh -P projectname and -G com.test.app
so that the user can be informed as -P : Project Name and -G : group Id .Please let me know the changes
Example:
#!/bin/bash
echo "the $1 eats a $2 every time there is a $3"
echo "bye:-)"
source - wikia
Check the Bash's documentation about Positional Parameters...
A positional parameter is a parameter denoted by one or more digits, other than the single digit 0. Positional parameters are assigned from the shell’s arguments when it is invoked, and may be reassigned using the set builtin command. Positional parameter N may be referenced as ${N}, or as $N when N consists of a single digit. Positional parameters may not be assigned to with assignment statements. The set and shift builtins are used to set and unset them (see Shell Builtin Commands). The positional parameters are temporarily replaced when a shell function is executed (see Shell Functions).
When a positional parameter consisting of more than a single digit is expanded, it must be enclosed in braces.
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
Right now I'm stuck with this project in having to pull information from an excel file to create users. The script requires the following.
Create accounts for the employees
Place them into his or her own department group
Set an initial password using his or her employee ID
Send an email containing their new account and password
show progress with dots on the screen
I'm getting close but am getting EOF errors on line 8 and 13 see script here
#!bin/bash
echo $(pwd)/employeesdata.xls
Path=$($pwd)/employeesdata.xls
read Path
if [ -e $Path ];
then
Username= [ grep $(Username) $Path | cut -f1 -d `]'
Password= [ grep $(Password) $Path | cut -f2 -d `]'
useradd -- b $Username
echo $Password | /usr/bin/passwd --stdin $Username
fi
exit
I know it doesn't have the email portion yet.
PS-UserScript: line 8: unexpected EOF while looking for matching `''
PS-UserScript: line 13: syntax error: unexpected end of file
You can use Spreadsheet::ParseExcel for this task:
First make sure cpanm is installed:
$ cpan App::cpanminus
Then install the module:
$ cpanm Spreadsheet::ParseExcel
Once installed, you will be able to use the parsing script that you have copied into your question. That script will fetch each cell one at a time, but you'll still need to do something with those values once read. Depending on how the spreadsheet is setup (if you provide a sample or at least the headers that would be helpful), you would want to gather the info you need as you iterate over the rows, and then perform the desired actions using the data you collected.
Also, I want to point out that the file you parse has to be in the older *.xls format. ParseExcel will not parse *.xlsx files, so first save in the older format using Excel if required.
This simple python script iterate over each cells/rows, that will be a good start I think :
#!/usr/bin/python
from openpyxl import load_workbook
wb = load_workbook(filename = 'file.xlsx', use_iterators = True)
ws = wb.get_sheet_by_name(name = 'Feuil1') # ws is now an IterableWorksheet
for row in ws.iter_rows(): # it brings a new method: iter_rows()
for cell in row:
print cell.internal_value