Shell scripting: Identify all the paths in a pattern - shell

I am trying to find the all the paths in a pattern and I am stuck. This is the structure of the directory
testdir
|-- dir with spaces
| |-- subdir
| | |
| | |-subfile.sh
| |
| +-- 1.sh
| |
| +-- 2.sh
|
+-- dir1
| |
| |
| +-- file.sh
|
+-- test.sh
this is the path pattern i have testdir/**/*
What i want
The output i am trying to get is
-flag testdir/dir\ with\ spaces/1.sh
-flag testdir/dir\ with\ spaces/2.sh
-flag testdir/dir\ with\ spaces/subdir
-flag testdir/dir\ with\ spaces/subdir/subfile.sh
-flag testdir/dir1
-flag testdir/dir1/file.sh
-flag testdir/test.sh
What i tried
pathpattern=testdir/**/*
echo $pathpattern
It prints the following
testdir/dir with spaces/1.sh testdir/dir with spaces/2.sh testdir/dir with spaces/subdir testdir/dir1/file.sh
I tried doing an echo of the path pattern but it didn't return everything.
I also dont know to handle entries that have a space. I tried looping through $pathpattern, but failed to differentiate between a new path and a path that has a space.

This should do it.
printf -- "-flag %q\n" testdir/**/*
However, this looks like probably a very poor way to accomplish ... something. Without knowledge of the actual end goal, it's hard to suggest how to do it properly. Typically, you don't want to produce a variable or string containing file names (let alone commands) and if you do, you shoud probably be using an array instead. But perhaps you simply want
for file in testdir/**/*; do
: ... something with "$file"
done
The array solution would look something like
#!/bin/bash
# ^ sh doesn't have arrays
array=($(printf " -test %q" testdir/**/*))
your --program --call ${array[#]} --more arguments

Related

How to obtain new filename from old filename in the shell script?

I have an executable program that have input and output likes
./my_exe -i filename_input -o filename_output
I want to use the program to run all filename in my folder that has structure likes
root
|-folder_A
|-abc.txt
|-folder_B
|cdf.txt
So, we can use for to do it. But the problem is that I want to automatically make the filename_output from the filename_input by adding the extension '_processed' before '.txt' likes abc.txt is input file name
. Then the output will be abc_processed.txt
How to do it in shell script? This is my current for code
for sub_folder in "${root_folder[#]}"
do
filename_input=$sub_folder/*.txt
filename_output= filename_input/*.txt/processed.txt
echo filename_output
done
The output of my script is root/folder_A/*processed.txt. I do not know why abc is lost
The right solution depends on what you want to do with it.
You should loop over the files you want to rename, not the directories.
for f in */*/*txt; do
echo "With path ${f} ==> ${f//.txt/processed.txt}"
base_f=${f##*/}
echo "Basenames: ${base_f} ==> ${base_f//.txt/processed.txt}"
done
You might want to use find ... | xargs for this when you want to call my_exe with these files.
Make sure your *processed.txt are not converted again!
$ tree root
root
|-- directory-A
| `-- abc.txt
`-- directory-B
`-- def.txt
2 directories, 2 files
$ find root -type f -exec sh -c 'echo ${1%.txt}_processed.txt' _ {} \;
root/directory-B/def_processed.txt
root/directory-A/abc_processed.txt
or:
$ for dir in root/*; do ( cd $dir; for file in *.txt;
do echo "$file --> ${file%.txt}_processed.txt"; done ) done
abc.txt --> abc_processed.txt
def.txt --> def_processed.txt

How to create named soft links in a makefile?

I'm exploring ways to improve code module integration and have found interest in using named soft links as opposed to include directories, mainly because that allows the integrator to set a directory name of any imported module to something guaranteed not to collide with the module built or any of its imported modules, as well as keeping imported modules from accidently intercepting eachother. However I'm not sure how to actually accomplish this in a makefile.
Here is the directory hierarchy and expected links:
+---proj1
| +---inc
| | head.h
| |
| \---src
| code.c
|
+---proj2
| +---inc
| | head.h
| |
| \---src
| code.c
|
\---proj3
| Makefile
|
\---src
| code.c
| head.h
|
+---A --> ../../proj1/inc
| head.h
|
\---B --> ../../proj2/inc
head.h
In proj3/src/code.c i would have:
#include "head.h"
#include "A/head.h"
#include "B/head.h"
I think I need some way to run ln -s for each {directory,name} tuple prior to compiling the source, putting the link in the same directory as the source being compiled. Parsing INC=dir1 dir2 is simple enough, but how to represent and run ln -s for each pair/tuple in such a list? Or, if having a whole command in each element (ln -s dir1 localname), how to exec all of them?
Other suggestions would be deeply appreciated.
Something like this?
linkdirs := A B
dir_A := ../proj1/src
dir_B := ../proj2/src
.PHONY: all symlinks
all: symlinks hello
symlinks:
$(eval $(patsubst %,ln -fs $$(dir_%) % &&,$(linkdirs)) true

Looping two files (Rename and Move)

First of all, this is the code;
#!/bin/bash
i=1;
while read line;
do
cp "$i.eps" "$line.eps"
while read line2;
do
mv "$line.eps" "$line2"
sed -i '1d' cate.txt
done < cate.txt
sed -i '1d' cate.txt
((i++))
done < Names.txt
cp "$i.eps" "$line.eps"
Let me explain; I have 2 files totally. One of them is named "Names.txt" which contains the name of files. And the other file is "cate.txt" which contains the name of directories. Also I have .eps files which has name like; 1.eps, 2.eps, etc...
So, what I would like to do is to read the first line in "Names.txt" and than change the first file's name with the first line, and than read first line in "cate.txt" and move the first file under the directory that I read in "cate.txt"
PS 1: I used sed command there because I was always reading the first line in "cate.txt". So, I thought after I read the first line, I can delete it and than read the first line again. But the code was not successful to do that.
PS 2: In this code I can read "Names.txt" and rename .eps files. But when I start reading the "cate.txt" the script doesn't work properly.
Thank you!
Assuming that names.txt and cate.txt have the same number of rows, you can join them together and use that output instead:
#!/bin/bash
i=1
while read filename dirname; do
mkdir -p $dirname
cp $i.file $dirname/$filename
((i++))
done < <(paste names.txt cate.txt)
Example before running:
$ tree
.
|-- 1.file
|-- 2.file
|-- 3.file
|-- cate.txt
`-- dirs.txt
$ cat names.txt
first_file
second_file
third_file
$ cat cate.txt
first_dir
second_dir
third_dir
And after:
$ tree
.
|-- 1.file
|-- 2.file
|-- 3.file
|-- cate.txt
|-- dirs.txt
|-- first_dir
| `-- first_file
|-- second_dir
| `-- second_file
`-- third_dir
`-- third_file
I am getting this error
nameAndMove: line 8: syntax error near unexpected token <'
nameAndMove: line 8:done < <(paste iconNames.rtf iconCate.rtf)'
I googled it and people say that process substitution is not allowed in my terminal. I use mac terminal.
Thank you

Bash finding files in subdirectories and move them into a new folder

Hi all I'm a bit stuck with a process that on the surface seems like it should be pretty simple, but I'm finding it challenging. It has been a while since I have done much bash scripting so perhaps I'm just rusty.
I am trying to traverse a directory tree and sort files into different subdirectories based on their extension. In each subdirectory I have a series of image files and I want to move all of the files that have the .RAW extension into a new subdir named RAW (create it if it doesn't exist) and leave the remaining files where they are. Oh yeah, and some of the folder and file names contain spaces just to make life more interesting.
The basic operations:
Loop over subdirectories
In each subdir
Check to see if files with the extension .RAW are there
If yes then create a new directory named RAW and move all of the matching files into there
Here is an example to clarify
Dir1
|--subdir 1
| |--file1.jpg
| |--file2.jpg
| |--file3.RAW
| |--file4.RAW
|
|--subdir 2
| |--file1.jpg
| |--file2.jpg
| |--file3.RAW
| |--file4.RAW
The result I want is:
Dir1
|--subdir 1
| |--RAW
| | |--file3.RAW
| | |--file4.RAW
| |
| |--file1.jpg
| |--file2.jpg
|
|--subdir 2
| |--RAW
| | |--file3.RAW
| | |--file4.RAW
| |
| |--file1.jpg
| |--file2.jpg
I started out trying to use a loop like
for dir in */ do cd $dir; mkdir RAW; for files in *.RAW do mv $files ./RAW; done; done
That's not quite what i want though and it doesn't play nicely with spaces in names.
I have played around a bit with find, but can't seem to get that to work. I feel I'm missing an elegant solution here. Any suggestions?
Try this command:
#!/bin/bash
find Dir1 -mindepth 1 -type f -name '*.RAW' | while read -r FILE; do
DIRNAME=${FILE%/*}
mkdir -p "$DIRNAME/RAW" && mv "$FILE" "$DIRNAME/RAW/"
done

Flatten a java project directory structure prepending the path to the file

I am trying to write a script (preferably in bash) to flatten a java projet directory structure prepending the path to the file. Example:
| src
| org
| apache
| file2.java
| file1.java
would result in:
| src
| org|apache|file2.java
| org|file1.java
The script should be recursive since the directory could have many subfolders.
cd src
for i in $(find . - name '*.java') ; do
echo cp \"$i\" $(echo "$i" | tr / _)
done
if it looks good(might barf if filenames contains spaces), pipe the result to sh

Resources