How to strip sub-directories from path using shell - linux

In a make file i want to strip some sub-directories from a path given in a variable. I figure i can use $(shell ...) to do it, so a sed one-liner or similar would do the trick i think. Any suitable make technique would do though.
The path contained in the variable typically looks like:
/repo/myrepo/products/foo/prod1/test/gtest/bin/XXX
or
/repo/myrepo/products/cool_products/bar/prod2/test/gtest/bin
And i want to strip everything after prod1 and prod2 above, giving the results:
/repo/myrepo/products/foo/prod1
/repo/myrepo/products/cool_products/bar/prod2
In other words, strip all directories starting with test/gtest which i can assume is in all the paths i will be applying this to. I have not been able to figure out a clean way to strip a different number of sub-directories.

sed 's#/test/gtest.*##g'
This will remove everything from /test/gtest to the end.
Sample:
AMD$ echo "/repo/myrepo/products/foo/prod1/test/gtest/bin/XXX" | sed 's#/test/gtest.*##g'
/repo/myrepo/products/foo/prod1

Another possibility, if you want to do it with functions internal to GNU make instead of invoking a separate program via $(shell ...), would be something like:
FULL_PATH = /repo/myrepo/products/foo/prod1/test/gtest/bin/XXX
STRIPPED_PATH := $(firstword $(subst /test/gtest, ,$(FULL_PATH)))
Basically this says "take $(FULL_PATH) and first replace the string /test/gtest with a space character everywhere it appears in the string, then return the first word of the resulting string".

Related

How do I exclude a character in Linux

Write a wildcard to match all files (does not matter the files are in which directory, just ask for the wildcard) named in the following rule: starts with a string “image”, immediately followed by a one-digit number (in the range of 0-9), then a non-digit char plus anything else, and ends with either “.jpg” or “.png”. For example, image7.jpg and image0abc.png should be matched by your wildcard while image2.txt or image11.png should not.
My folder contained these files imag2gh.jpeg image11.png image1agb.jpg image1.png image2gh.jpg image2.txt image5.png image70.jpg image7bn.jpg Screenshot .png
If my command work it should only display image1agb.jpg image1.png image2gh.jpg image5.png image70.jpg image7bn.jpg
This is the command I used (ls -ad image[0-9][^0-9]*{.jpg,.png}) but I'm only getting this image1agb.jpg image2gh.jpg image7bn.jpg so I'm missing (image1.png image5.png)Kali Terminal and what I did
ls -ad image[0-9][!0-9]*{.jpg,.png}
Info
Character ranges like [0-9] are usually seen in RegEx statements and such. They won't work as shell globs (wildcards) like that.
Possible solution
Pipe output of command ls -a1
to standard input of the grep command (which does support RegEx).
Use a RegEx statement to make grep filter filenames.
ls -a1|grep "image"'[[:digit:]]\+[[:alpha:]]*\.\(png\|jpg\)'

Removing changing pattern from filenames in directory in Linux

I have a directory containing files following the following naming convention:
Label_0000_AA.gz
Label_0001_BB.gz
Label_0002_CC.gz
...
All I want to do is to rename these files so that the _#### number pattern is removed, resulting in:
Label_AA.gz
Label_BB.gz
Label_CC.gz
...
but only up to a certain number. E.g.: I may have 10000 files but might only want to remove the pattern in the first 3000. Would this be possible using something like bash?
If you don't have prename or rename -
(assuming the names are consistent)
for f in Label_[0-9][0-9][0-9][0-9]_[A-Z][A-Z].gz
do mv "$f" "${f//_[0-9][0-9][0-9][0-9]/}"
done
To just do a certain range -
for n in {0000..2999}
do for f in Label_${n}_??.gz
do mv $f ${f//_$n/}
done
done
You're sure there are not collisions?
If you can name the pattern you want to change/remove in a regex you can use the command prename:
prename 's/_[0-3][[:digit:]]{3}_/_/g' Label_*.gz
This regex would only remove numbers 0000-3999.
Using the flag -n does a "dry-run" and shows what it would do.
Edit: Thanks #KamilCuk to remind me about two renames. I made it clear and changed the name to prename.

bash handling of quotation marks in filename

I am trying to remove and replace quotation marks that are present in a file name. For example, I would like to change:
$ ls
abc"def"ghi"jkl"mno
to this
$ ls
abc:def:ghi:jkl:mno
In trying to solve this, I came across How to rename a bunch of files to eliminate quote marks, which is exactly what I want to do. However, it didn't work for my case. To figure out why, I tried creating a test file like this:
$ touch abba\"abba\"cde\"cde\"efef
With this file, the solutions I came across (such as mentioned above) worked. But why didn't it work for the first file?
One thing I discovered was that bash command completion sees them differently. If I type in
$ ls abb<tab>
bash will complete the filename like so:
$ abba\"abba\"cde\"cde\"efef
just as I created it. But for the original file, bash completion went like this:
$ ls abc<tab>
results in
$ abc"def"ghi"jkl"mno
So in the test case file, there is an escape of the quotation marks, and in the other case (the file I really want to rename), there is no escaping of the the quotation marks. I don't know how the original files were named.
Can anyone explain why bash sees these names differently, and how I would go about renaming my file?
Here is two ways to rename a file with "(quotation) mark,
option 1: With escape character \
mv abc\"cdf\"efg\"hij newFileName
option 2: By using '(single quote)
mv 'abc"cdf"efg"hij' newFileName
Note: using special charaters like :(colon) in file name might not be a good idea,
and regarding the auto completion, it usually fill the name with escape character, example
ls abc<tab> will complete the name to ls abc\"cdf\"efg\"hij
unless you start the name with a quote, example
ls 'abc<tab> will complete the name to ls 'abc"cdf"efg"hij'

Why $$PWD instead of $PWD in TI x-loader makefile for omap devices

I started to analyse the TI X-Loader, including it's makefiles. I found the following lines in the top makefile:
TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
and
ifeq (include/config.mk,$(wildcard include/config.mk))
...
Regarding the first line: i know that "$PWD" means the value of PWD (the working directory)
My question:
why the double dollar sign in this special case?
Regarding the second line: I'm trying to understand what is compared and why.
I already red the GNU MAKE manual wildcard explanation. I'm still missing something.
My questions:
what is the "$(wildcard" for?
Which config.mk files exactly are compared to each other?
Why are they compared? (this question is more about the makefile structure)
Thanks for your help in advance.
Martin
In make, you escape a dollar sign (so that it's not expanded by make) using two dollar signs ($$). So, if you write $PWD then make will interpret the $P as a make variable reference, which is likely not set and so empty, and the result (passed to the shell) will be WD. If you use $$PWD then the dollar sign is escaped and the result passed to the shell command will be $PWD which is what you want.
For the second line, the wildcard function will, among other things, expand to the empty string if there are no files that match the wildcard. So this invocation of wildcard is testing to see if the file include/config.mk exists or not. If it does, then the result of the function will be include/config.mk and the ifeq test will be true. If it doesn't then the result will be the empty string and the ifeq test will be false.
Nothing here is comparing the contents or timestamps or anything else of include/config.mk. This is purely a "does this file exist?" test.

Using wildcards to exclude files with a certain suffix

I am experimenting with wildcards in bash and tried to list all the files that start with "xyz" but does not end with ".TXT" but getting incorrect results.
Here is the command that I tried:
$ ls -l xyz*[!\.TXT]
It is not listing the files with names "xyz" and "xyzTXT" that I have in my directory. However, it lists "xyz1", "xyz123".
It seems like adding [!\.TXT] after "xyz*" made the shell look for something that start with "xyz" and has at least one character after it.
Any ideas why it is happening and how to correct this command? I know it can be achieved using other commands but I am especially interested in knowing why it is failing and if it can done just using wildcards.
These commands will do what you want
shopt -s extglob
ls -l xyz!(*.TXT)
shopt -u extglob
The reason why your command doesn't work is beacause xyz*[!\.TXT] which is equivalent to xyz*[!\.TX] means xyz followed by any sequence of character (*) and finally a character in set {!,\,.,T,X} so matches 'xyzwhateveryouwant!' 'xyzwhateveryouwant\' 'xyzwhateveryouwant.' 'xyzwhateveryouwantT' 'xyzwhateveryouwantX'
EDIT: where whateveryouwant does not contain any of !\.TX
I don't think this is doable with only wildcards.
Your command isn't working because it means:
Match everything that has xyz followed by whatever you want and it must not end with sequent character: \, .,T and X. The second T doesn't count as far as what you have inside [] is read as a family of character and not as a string as you thought.
You don't either need to 'escape' . as long as it has no special meaning inside a wildcard.
At least, this is my knowledge of wildcards.

Resources