How to rename multiple filenames in cshell script? - unix

I have a c shell script which has the following two lines, it creates a directory and copies some files into it. My question is the following - the files being copied look like this abc.hello, abc.name, abc.date, etc... How can i strip the abc and just copy them over as .hello, .name, .date.. and so forth. I'm new to this.. any help will be appreciated!
mkdir -p $home_dir$param
cp /usr/share/skel/* $home_dir$param

You're looking for something like basename:
In Bash, for example, you could get the base name, file suffix like this:
filepath=/my/folder/readme.txt
filename=$(basename "$filepath") # $filename == "readme.txt"
extension="${filename##*.}" # $extension == "txt"
rootname="${filename%.*}" # $rootname == "readme"
ADDENDUM:
The key takeaway is "basename". Refer to the "man basename" page I linked to above. Here's another example that should make things clearer:
basename readme.txt .txt # prints "readme"
"basename" is a standard *nix command. It works in any shell; it's available on most any platform.
Going forward, I would strongly discourage you from writing scripts in csh, if you can avoid it:
bash vs csh vs others - which is better for application maintenance?
Csh Programming Considered Harmful

Related

Combine multiple scripts in an "index.html" like fashion?

Is there a standard way in a unixesque (sh/bash/zsh) system to execute a group of scripts as if the group of scripts was one script? (Think index.html). The point is to avoid additional helper scripts like you usually find and keep small programs self sufficient and easier to maintain.
Say I have two (in bold) ruby scripts.
/bin /bin/foo_master /bin/foo_master/main
/bin/foo_master/helper.rb
So now when I execute foo_master
seo#macbook ~ $foo_master [/bin/foo_master/main]: Make
new friends, but keep the old. [/bin/foo_master/helper.rb]: One
is silver and the other gold.
If you're trying to do this without creating a helper script, the typical way to do this would just be to execute both (note: I'll use : $; to represent the shell prompt):
: $; ./main; ./helper.rb
Now, if you're trying to capture the output of both into a file, say, then you can group these into a subshell, with parenthesis, and capture the output of the subshell as if it was a single command, like so:
: $; (./main; ./helper.rb) > index.html
Is this what you're after? I'm a little unclear on what your final goal is. If you want to make this a heavily repeatable thing, then one probably would want to create a wrapper command... but if you just want to run two commands as one, you can do one of the above two options, and it should work for most cases. (Feel free to expand the question, though, if I'm missing what you're after.)
I figured out how to do this in a semi-standard complaint fashion.
I used the eval syntax in shell scripting to lambda evaluate the $PATH at runtime. So in my /etc/.zshrc
$REALPATH = $PATH
$PATH = $REALPATH:`find_paths`
where find_paths is a function that recursively searches the $PATH directories for folders (pseudocode below)
(foreach path in $PATH => ls -d -- */)
So we go from this:
seo#macbook $ echo $PATH
/bin/:/usr/bin/
To this, automagically:
seo#macbook $ echo $PATH
/bin/:/usr/bin/:/bin/foo_master/
Now I just rename main to "foo_master" and voilĂ ! Self contained executable, dare I say "app".
Yep that's an easy one!
#!/bin/bash
/bin/foo_master/main
/bin/foo_master/helper.rb
Save the file as foo_master.sh and type this in the shell:
seo#macbook ~ $sudo chmod +x foo_master.sh
Then to run type:
seo#macbook ~ $./foo_master.sh
EDIT:
The reason that an index.html file is served at any given directory is because the HTTP Server explicitly looks for one. (In server config files you can specify names of files to look for to server like index.html i.e. index.php index.htm foo.html etc). Thus it is not magical. At some point, a "helper script" is explicitly looking for files. I don't think writing a script like above is a step you can skip.

How to use mv command to rename multiple files in unix?

I am trying to rename multiple files with extension xyz[n] to extension xyz
example :
mv *.xyz[1] to *.xyz
but the error is coming as - " *.xyz No such file or directory"
Don't know if mv can directly work using * but this would work
find ./ -name "*.xyz\[*\]" | while read line
do
mv "$line" ${line%.*}.xyz
done
Let's say we have some files as shown below.Now i want remove the part -(ab...) from those files.
> ls -1 foo*
foo-bar-(ab-4529111094).txt
foo-bar-foo-bar-(ab-189534).txt
foo-bar-foo-bar-bar-(ab-24937932201).txt
So the expected file names would be :
> ls -1 foo*
foo-bar-foo-bar-bar.txt
foo-bar-foo-bar.txt
foo-bar.txt
>
Below is a simple way to do it.
> ls -1 | nawk '/foo-bar-/{old=$0;gsub(/-\(.*\)/,"",$0);system("mv \""old"\" "$0)}'
for detailed explanation check here
Here is another way using the automated tools of StringSolver. Let us say your first file is named abc.xyz[1] a second named def.xyz[1] and a third named ghi.jpg (not the same extension as the previous two).
First, filter the files you want by giving examples (ok and notok are any words such that the first describes the accepted files):
filter abc.xyz[1] ok def.xyz[1] ok ghi.jpg notok
Then perform the move with the filter it created:
mv abc.xyz[1] abc.xyz
mv --filter --all
The second line generalizes the first transformation on all files ending with .xyz[1].
The last two lines can also be abbreviated in just one, which performs the moves and immediately generalizes it:
mv --filter --all abc.xyz[1] abc.xyz
DISCLAIMER: I am a co-author of this work for academic purposes. Other examples are available on youtube.
I think mv can't operate on multiple files directly without loop.
Use rename command instead. it uses regular expressions but easy to use once mastered and more powerful.
rename 's/^text-to-replace/new-text-you-want/' text-to-replace*
e.g to rename all .jar files in a directory to .jar_bak
rename 's/^jar/jar_bak/' jar*

How can I compare the output of two unix commands to find the difference?

I prefer not to create new files. I want to accomplish something similar to:
cmd1 > a
cmd2 > b
cat a b b | sort | uniq -u
but without using files a and b.
Unix utilities are generally file oriented, so nothing quite does what you want.
However, zsh can autocreate temporary files with the following syntax:
diff =(cmd1) =(cmd2)
It can also create temporary named pipes (or use the special files /dev/fdn to reference anonymous pipes) with
diff <(cmd1) <(cmd2)
However, many diffs call lseek() on their input, so won't work with named pipes.
(diff is in general a more useful command for comparing very similar output than your pipeline above.)
See the "process substitution" section of the "zshexpn" man page for more details.

How to quickly rename a bunch of files in the folder

I have a bunch of files that are named 'something_12345.doc' (any 5-digit number, not necessarily 12345). I need to rename them all to just 'something.doc'. This is a Unix filesystem, and I suspect there's a way to do this with just one command... Can any Unix regular expressions guru help?
Thanks!
#OP, the shell has already expanding your pattern for you, there in your mv statement, you don't have to specify the pattern for 5 digits again.
for file in *_[0-9][0-9][0-9][0-9][0-9].doc
do
echo mv "$file" "${file%_*}.doc"
done
This question was asked a lot of times on SO:
bash script to rename all files in a directory?
bash Linux - Massive folder rename
How to do a mass rename?
https://stackoverflow.com/questions/7137/replacing-one-string-in-a-bunch-of-file-names-with-another
My personal preference goes to mmv. But see "Mass Rename/copy/link Tools".
rename 's/_[0-9][0-9][0-9][0-9][0-9]//' *.doc
use sed
ls *.doc | sed 's:\([^0-9_]\)[0-9_][0-9_]*\.doc:$(mv & \1.doc)' | /bin/bash
Yes, rename takes perl style regular expressions. Do a man rename.
On FreeBSD, you might be interested in the sysutils/renameutils port. The command qmv opens your $EDITOR and allows you to specify all file renames in a reasonably comfortable environment. I personally prefer the qmv -fdo (single column) format.

paste without temporary files in Unix

I'm trying to use the Unix command paste, which is like a column-appending form of cat, and came across a puzzle I've never known how to solve in Unix.
How can you use the outputs of two different programs as the input for another program (without using temporary files)?
Ideally, I'd do this (without using temporary files):
./progA > tmpA;
./progB > tmpB; paste tmpA tmpB
This seems to come up relatively frequently for me, but I can't figure out how to use the output from two different programs (progA and progB) as input to another without using temporary files (tmpA and tmpB).
For commands like paste, simply using paste $(./progA) $(./progB) (in bash notation) won't do the trick, because it can read from files or stdin.
The reason I'm wary of the temporary files is that I don't want to have jobs running in parallel to cause problems by using the same file; ensuring a unique file name is sometimes difficult.
I'm currently using bash, but would be curious to see solutions for any Unix shell.
And most importantly, am I even approaching the problem in the correct way?
Cheers!
You do not need temp files under bash, try this:
paste <(./progA) <(./progB)
See "Process Substitution" in the Bash manual.
Use named pipes (FIFOs) like this:
mkfifo fA
mkfifo fB
progA > fA &
progB > fB &
paste fA fB
rm fA fB
The process substitution for Bash does a similar thing transparently, so use this only if you have a different shell.
Holy moly, I recent found out that in some instances, you can get your process substitution to work if you set the following inside of a bash script (should you need to):
set +o posix
http://www.linuxjournal.com/content/shell-process-redirection
From link:
"Process substitution is not a POSIX compliant feature and so it may have to be enabled via: set +o posix"
I was stuck for many hours, until I had done this. Here's hoping that this additional tidbit will help.
Works in all shells.
{
progA
progB
} | paste

Resources