Parameter Substitution - Remove the part of the string after the pattern - bash

Let's say I have a path which looks like the following:
/A/B/C/DIRECTORY/D/E/F
Now, what I want to achieve using parameter substitution, is cutting of the part of the path after DIRECTORY, no matter where in the path the DIRECTORY is positioned (A, B, C, etc. just stand for random directory names).
After substitution:
/A/B/C/DIRECTORY
This is what I've tried so far:
#!/bin/bash
if [[ $# < 1 ]]
then
echo "Usage: $0 DIRECTORY"
fi
CURRENT_DIRECTORY=$(pwd)
DIRECTORY=$1
cd ${CURRENT_DIRECTORY%!(DIRECTORY)/*}
Obviously, this doesn't work. I could implement this using awk or sed but I'm interested if it is possible using only parameter substitution.

May be this can help -
[jaypal:~/Temp] D="A/B/C/DIRECTORY/D/E/F"
[jaypal:~/Temp] echo $D
A/B/C/DIRECTORY/D/E/F
[jaypal:~/Temp] c=${D%/*/*/*}
[jaypal:~/Temp] echo $c
A/B/C/DIRECTORY

[ghoti#pc ~]$ D="/A/B/C/foo/D/E"
[ghoti#pc ~]$ echo "${D/foo*/}"
/A/B/C/
of course, this isn't perfect:
[ghoti#pc ~]$ D="/A/B/C/foobar/D/foo/E"
[ghoti#pc ~]$ echo "${D/foo*/}"
/A/B/C/
Read the bash man page and search for "Pattern substitution".

Try next solution:
cd ${CURRENT_DIRECTORY/${DIRECTORY}*/""}
EDIT:
More accurate answer would be appending your directory after removing last part:
cd ${CURRENT_DIRECTORY/${DIRECTORY}*/""}$DIRECTORY

Thanks to Birei, I came to this (not perfect but good enough solution:
#/bin/bash
if [[ $# < 1 ]]
then
echo "Usage: $0 BASENAME"
fi
echo ${PWD/%$1*/$1}
Example:
$ PWD=/home/ltorvalds/workspace
$ ./up.sh ltorvalds
/home/ltorvalds

Related

Some tips to improve a bash script for count fastq files

Hi guys I got this bash one line that i wish to make a script
for i in 'ls *.fastq.gz'; do echo $(zcat ${i} | wc -l)/4|bc; done
I would like to make it as a script to read from a data dir and print out the result with the name of the file.
I tried to put the dir in front of the 'data/*.fastq.gz' but got am error No such dir exist...
I would like some like this:
name1.fastq.gz 1898516
name2.fastq.gz 2467421
namen.fastq.gz 1234532
I am not experienced in bash.
Could you guys give a help?
Thanks
Take the dir as an argument, but default to the current dir if it's not set.
dir="${1-.}"
Then put it in the glob: "$dir"/*.fastq.gz
As well:
Quote variables and command expansions.
Don't parse ls.
Don't trust echo with arbitrary data (filenames). Use printf instead.
Use an end-of-options flag -- when giving filenames to commands.
I prefer to not have any inline command expansions, but that's just personal preference
Putting it together:
#!/bin/bash
dir="${1-.}"
for file in "$dir"/*.fastq.gz; do
printf '%s ' "$file"
lines="$(zcat -- "$file" | wc -l)"
bc <<< "$lines/4" # Using a here-string (Bash feature)
done
There is no need to escape to bc for integer math (divide by 4), or to use 'ls' to enumerate the files. The original version will do with minor changes:
#!/bin/bash
dir="${1-.}"
for i in "$dir"/*.fastq.gz; do
lines=$(zcat "${i}" | wc -l)
printf '%s %d\n' "$i" "$((lines/4))"
done

Shell script for replacing characters?

I'm trying to write a shell script that takes in a file(ex. file_1_2.txt) and replaces any "_" with "."(ex. file.1.2.txt). This is what I have but its giving me a blank output when I run it.
read $var
x= `echo $var | sed 's/\./_/g'`
echo $x
I'm trying to store the changed filename in the variable "x" and then output x to the console.
I am calling this script by writing
./script2.sh < file_1_2.txt
There is two problems. First, your code has some bugs:
read var
x=`echo $var | sed 's/_/\./g'`
echo $x
will work. You had an extra $ in read var, a space too much (as mentioned before) and you mixed up the replacement pattern in sed (it was doing the reverse of what you wanted).
Also if you want to replace the _ by . in the filename you should do
echo "file_1_2.txt" | ./script2.sh
If you use < this will read the content of `file_1_2.txt" into your script.
Another solution, with bash only:
$ x=file_1_2.txt; echo "${x//_/.}"
file.1.2.txt
(See “Parameter expansion” section in bash manual page for details)
And you can also do this with rename:
$ touch file_1_2.txt
$ ls file*
file_1_2.txt
$ rename 'y/_/\./' file_1_2.txt
$ ls file*
file.1.2.txt
Threre is not need for sed as bash supports variable replacement:
$ cat ./script2
#!/bin/bash
ofile=$1
nfile=${ofile//_/./}
echo mv "$ofile" "$nfile"
$ ./script2 file_1_2.txt
mv "file_1_2.txt" "file.1.2.txt"
Then just remove echo if you are satisfied with the result.

Printing a newline

GAAAAAAAAAAAAAAH I don't know why I'm struggling so much with this.
All I want to do is make:
file="$a"[command-here]"$b"
to make $file=
a [newline]
b
And yet no matter WHAT echo or printf I try to use, I cannot get it to work!! I just want a newline between a and b. Can someone bring me out of my misery?
file="$a""echo -e '\n'""$b" does not work, nor can any combination I can think of.
You can use:
a='foo'
b='bar'
file="$a"$'\n'"$b"
echo "$file"
foo
bar
Or use print -v:
unset file
printf -v file "$a\n$b"
echo "$file"
foo
bar
sh and similar shells preserve newlines in quoted strings. You could do this:
file="$a
$b"
for example:
$ a=foo
$ b=bar
$ file="$a
> $b"
$ echo "$file"
foo
bar

String manipulation Bash-Extensions

In my script I'm trying to take a string, then output the extension of a string if it has one. So essentially I take the basename of a file, then output anything that comes after a period.
What's the syntax to do something like this?
For example
dotcutter.sh
file=testfile.jpg
the script should output .jpg
EDIT:
I've solved my problem now with:
file=$(basename "$1" )
stub=${file%.*}
echo ${file#"$stub"}
Which reduces my argument to a basename, thank you all.
$ file=testfile.jpg
$ echo ${file##*.}
jpg
$ file=testfile.ext1.ext2
$ echo ${file##*.}
ext2
$ file=noextension
$ echo ${file##*.}
noextension
Notice that it doesn't work if the file has no extension. If that's important then try this two-step solution:
$ file=testfile.ext1.ext2
$ stub=${file%.*}
$ echo ${file#"$stub"}
.ext2
Or this regex-based one, which will only call echo if there's actually an extension. (&& is shorthand for "if then".)
$ regex='(\.[^.]*)$'
$ file=testfile.ext1.ext2
$ [[ $file =~ $regex ]] && echo ${BASH_REMATCH[1]}
.ext2
$ file=noextension
$ [[ $file =~ $regex ]] && echo ${BASH_REMATCH[1]}
See also:
basename(1)
dirname(1)
Bash FAQ: How can I use parameter expansion? How can I get substrings? How can I get a file without its extension, or get just a file's extension?]
Try the following code :
file=testfile.jpg
echo .${file#*.}
That use parameter expansion

shell script to count readable files

How can I write a shell script file_readable which:
accepts some number of names as arguments,
checks each name to see if it is a regular file and readable, and
outputs a count of the number of such files.
For example:
$ sh file_readable /etc/fstab /etc/ssh/ssh_host_rsa_key /etc/does-not-exist
1
Of these, only /etc/fstab is likely to both exist and be readable.
So far I have put this together but it does not work correctly - can anybody help me please ?:
#!/bin/sh
for filename in "$#"
do
if test -f "$filename"
then echo | wc -l
else echo $?
fi
done
then echo | wc -l
If file exists and is a regular you print number of lines in empty string plus "\n", which is equal 1 always. Sound not quite usable, isn't it?
All you need is incrementing some counter and printing it in the end.
#!/bin/sh
readable_files=0
for filename in "$#"; do
if test -f "$filename"; then
readable_files=$(( readable_files + 1 ))
fi
done
echo "${readable_files}"

Resources