Shell script print the path of all sub directory - shell

My Script:
cd /var/www/try/
sort -u
files="$(find -L "/var/www/try/" -type d)"
echo "Count: $(echo -n "$files" | wc -l)"
echo "$files" | while read file; do
echo $file >> filename.csv
done
Output :
/var/www/try
/var/www/try/cat
Output Should be :
var-www-try
var-www-try-cat
Second Case :
any character except / as some fo my folder name contain / like for e.g.
"tv/dvd"
Output genrated :
/var/www/try/cat/tv/dvd
Output Should be :
var-www-try-cat-tv/dvd-

Have a look at sed, which is a popular tool for string replacing tasks.
>> x=$(echo '/var/www/try/cat/tv/' | sed 's/\//-/g')
>> echo $x
-var-www-try-cat-tv-
>> x=${x:1}
>> echo $x
var-www-try-cat-tv-
edit:
In response to your second case:
as some fo my folder name contain /
Maybe there's a misunderstanding here but you should not have a / in a filename. See Is it possible to use "/" in a filename?

Related

Shell: Add string to the end of each line, which match the pattern. Filenames are given in another file

I'm still new to the shell and need some help.
I have a file stapel_old.
Also I have in the same directory files like english_old_sync, math_old_sync and vocabulary_old_sync.
The content of stapel_old is:
english
math
vocabulary
The content of e.g. english is:
basic_grammar.md
spelling.md
orthography.md
I want to manipulate all files which are given in stapel_old like in this example:
take the first line of stapel_old 'english', (after that math, and so on)
convert in this case english to english_old_sync, (or after that what is given in second line, e.g. math to math_old_sync)
search in english_old_sync line by line for the pattern '.md'
And append to each line after .md :::#a1
The result should be e.g. of english_old_sync:
basic_grammar.md:::#a1
spelling.md:::#a1
orthography.md:::#a1
of math_old_sync:
geometry.md:::#a1
fractions.md:::#a1
and so on. stapel_old should stay unchanged.
How can I realize that?
I tried with sed -n, while loop (while read -r line), and I'm feeling it's somehow the right way - but I still get errors and not the expected result after 4 hours inspecting and reading.
Thank you!
EDIT
Here is the working code (The files are stored in folder 'olddata'):
clear
echo -e "$(tput setaf 1)$(tput setab 7)Learning directories:$(tput sgr 0)\n"
# put here directories which should not become flashcards, command: | grep -v 'name_of_directory_which_not_to_learn1' | grep -v 'directory2'
ls ../ | grep -v 00_gliederungsverweise | grep -v 0_weiter | grep -v bibliothek | grep -v notizen | grep -v Obsidian | grep -v z_nicht_uni | tee olddata/stapel_old
# count folders
echo -ne "\nHow much different folders: " && wc -l olddata/stapel_old | cut -d' ' -f1 | tee -a olddata/stapel_old
echo -e "Are this learning directories correct? [j ODER y]--> yes; [Other]-->no\n"
read lernvz_korrekt
if [ "$lernvz_korrekt" = j ] || [ "$lernvz_korrekt" = y ];
then
read -n 1 -s -r -p "Learning directories correct. Press any key to continue..."
else
read -n 1 -s -r -p "Learning directories not correct, please change in line 4. Press any key to continue..."
exit
fi
echo -e "\n_____________________________\n$(tput setaf 6)$(tput setab 5)Found cards:$(tput sgr 0)$(tput setaf 6)\n"
#GET && WRITE FOLDER NAMES into olddata/stapel_old
anzahl_zeilen=$(cat olddata/stapel_old |& tail -1)
#GET NAMES of .md files of every stapel and write All to 'stapelname'_old_sync
i=0
name="var_$i"
for (( num=1; num <= $anzahl_zeilen; num++ ))
do
i="$((i + 1))"
name="var_$i"
name=$(cat olddata/stapel_old | sed -n "$num"p)
find ../$name/ -name '*.md' | grep -v trash | grep -v Obsidian | rev | cut -d'/' -f1 | rev | tee olddata/$name"_old_sync"
done
(tput sgr 0)
I tried to add:
input="olddata/stapel_old"
while IFS= read -r line
do
sed -n "$line"p olddata/stapel_old
done < "$input"
The code to change only the english_old_sync is:
lines=$(wc -l olddata/english_old_sync | cut -d' ' -f1)
for ((num=1; num <= $lines; num++))
do
content=$(sed -n "$num"p olddata/english_old_sync)
sed -i "s/"$content"/""$content":::#a1/g"" olddata/english_old_sync
done
So now, this need to be a inner for-loop, of a outer for-loop which holds the variable for english, right?
stapel_old should stay unchanged.
You could try a while + read loop and embed sed inside the loop.
#!/usr/bin/env bash
while IFS= read -r files; do
echo cp -v "$files" "${files}_old_sync" &&
echo sed '/^.*\.md$/s/$/:::#a1/' "${files}_old_sync"
done < olddata/staple_old
convert in this case english to english_old_sync, (or after that what is given in second line, e.g. math to math_old_sync)
cp copies the file with a new name, if the goal is renaming the original file name from the content of the file staple_old then change cp to mv
The -n and -i flag from sed was ommited , include it, if needed.
The script also assumes that there are no empty/blank lines in the content of staple_old file. If in case there are/is add an addition test after the line where the do is.
[[ -n $files ]] || continue
It also assumes that the content of staple_old are existing files. Just in case add an additional test.
[[ -e $files ]] || { printf >&2 '%s no such file or directory.\n' "$files"; continue; }
Or an if statement.
if [[ ! -e $files ]]; then
printf >&2 '%s no such file or directory\n' "$files"
continue
fi
See also help test
See also help continue
Combining them all together should be something like:
#!/usr/bin/env bash
while IFS= read -r files; do
[[ -n $files ]] || continue
[[ -e $files ]] || {
printf >&2 '%s no such file or directory.\n' "$files"
continue
}
echo cp -v "$files" "${files}_old_sync" &&
echo sed '/^.*\.md$/s/$/:::#a1/' "${files}_old_sync"
done < olddata/staple_old
Remove the echo's If you're satisfied with the output so the script could copy/rename and edit the files.

Issue with Bash variables

I'm trying to make a code for finding the number and type of atoms from a file.
The file B.txt has few names of the atoms in it and is read to go into the specific atom directory. The file input has the values of the positions and atom types in it. But I cannot store the name of atom as atom_1, atom_2, atom_3 etc..
If I change the atom_$i to atom, then the code works perfectly.
I expect the output to be atom_1=X,numberofatoms_1=100, atom_2=Y, numberofatoms_2=200 etc and so on.
The error is something like:
2(total number of types of atoms)
bash: atom_1=x: command not found
cd ~/A/
cat ~/A/B.txt | while read line
do
cd folder_"$line"
sed -n 6p input> temp1.txt
sed -n 7p input > temp2.txt
atoms= wc -w < temp1.txt > junk
#echo ${atoms}
typeset -i atoms=$(cat junk)
i=1
numberofatoms=0
echo ${atoms}
while [ $i -le $atoms ]
do
ptri=$( echo "scale=2; $i" | bc)
atom="$(cat temp1.txt | sed -n '1p'| cut -d' ' -f$ptri)" > junk
echo $atom
# next section is the code for counting the total number of atomsin the system
noa=$(cat temp2.txt | sed -n '1p'| cut -d' ' -f$ptri)
numberofatoms_$i=$(( $numberofatoms + $noa ))
i=`expr $i + 1`
done
echo "number of atoms = " $numberofatoms
cd ..
rm junk
rm temp1
rm temp2
done

assign stat|grep|awk to a variable in bash

I have a file of filenames, and I need to be able to get the size of these files using bash.
I have the following script which does that, but It prints the filename and the size on different lines, i'd prefer it to do it all on one line if possible.
#!/bin/sh
filename="$1"
while read -r line
do
name=$line
vars=(`echo $name | tr '.' ' '`)
echo $name
stat -x $name | grep Size: | awk '{ print $2 }'
done < "$filename"
I'd love to have it of the form:
filename: $size
How can I do this?
(I am using OSX hence the slightly odd version of stat.)
Pass -n to the echo to prevent a trailing newline from being added. So change
echo $name
to
echo -n $name
and to add the : separator between the file name and file size
echo -n ${name}": "
This should do the trick:
while read f
do
echo "${f} : $(stat -L -c %s ${f})"
done < "${filename}"
echo $name: $(stat -x $name | sed -n '/^Size:/s///p')

In a unix box, I am taking a list of files as input. If it is found, return the path otherwise return a message "filename file not found"

I have used the find command for this, but it doesnt return any message when a file is not found.
And I want the search to be recursive and return a message "not found" when a file is not found.
Here's the code I have done so far. Here "input.txt" contains the list of files to be searched.
set `cat input.txt`
echo $#
for i in $#
do
find $HOME -name $i
done
Try this:
listfile=input.txt
exec 3>&1
find | \
grep -f <( sed 's|.*|/&$|' "$listfile" ) | \
tee /dev/fd/3 | \
sed 's|.*/\([^/]*\)$|\1|' | \
grep -v -f - "$listfile" | \
sed 's/$/ Not found/'
exec 3>&-
open file descriptor 3
find the files
see if they're on the list (use sed to
send a copy of the found ones to file descriptor 3
strip off the directory name
get a list of the ones that don't appear
add the "Not found" message
close file descriptor 3
Output looks like:
/path/to/file1
/path/somewhere/file2
foo Not found
bar Not found
No loops necessary.
Whats wrong with using a script. I hope this will do.
#!/bin/bash -f
for i in $#
do
var=`find $HOME -name $i`
if [ -z "$var"]
then
var="File not found"
fi
echo $var
done
You can use the shell builtin 'test' to test the existence of a file. There is also an alternative syntax using square brackets:
if [ -f $a ]; then # Don't forget the semicolon.
echo $a
else
echo 'Not Found'
fi
Here is one way - create a list of all the files to grep against. If your implementation supports
grep -q otherwise use grep [pattern] 2&>1 >/dev/null....
find $HOME -type f |
while read fname
do
echo "$(basename $fname) $fname"
done > /tmp/chk.lis
while read fname
do
grep -q "^$fname" /tmp/chk.lis
[ $? -eq 0 ] && echo "$fname found" || echo "$fname not found"
done < /tmp/chk.lis
All of this is needed because POSIX find does not return an error when a file is not found
perl -nlE'say-f$_?$_:"not found: $_"' file

How to get $this->translate('Content') => Content in a Textfile

I am looking for a shell script which scans a direcotry and all its subdirectories for .php and .phtml files. Within these files, I am looking for $this->translate('') statements (also $this->view->translate('')) and I want to save the content of these statements in a textfile.
The problem is, that there are several different types of this statements:
$this->translate('Single Quotes') // I need: Single Quotes
$this->translate("Double Quotes") // I need: Double Quotes
$this->translate('Single quotes with %1$s placeholders', $xy) // I need: Single quotes with %1$s placeholders
$this->translate("Double quotes with %1\$s", $xy) // I need: Dobule quotes with %1$s
$this->view->translate('With view') // I need: With view
$this->view->translate("With view 2") // I need: With view 2
$this->translate('Single Quotes with "Doubles"') // I need: Single Quotes with "Doubles"
$this->translate("Double Quotes with 'Singles') // I need: Double Quotes with 'Singles'
I have already programmed a script and a guy from starmind.com sent me the following lines:
echo -n > give_me_your_favorite_outfile_name.txt
for i in `find . -iname '*php' `
do
echo -n "Processing $i ..."
# echo " +++++++ from $i ++++++++" >> give_me_your_favorite_outfile_name.txt
cat $i | sed -n -e '/->translate(*/p' | sed -e 's/\(.*->translate(.\)\([a-z A-Z \d092\d039\d034]*\)\(.*\)/\2/g' | sed -e 's/\(.*\)\(\d039\)/\1/g' | sed -e 's/\(.*\)\(\d034\)/\1/g' >> give_me_your_favorite_outfile_name.txt
echo " done"
done
for i in `find . -iname '*phtml' `
do
echo -n "Processing $i ..."
# echo " +++++++ from $i ++++++++" >> give_me_your_favorite_outfile_name.txt
cat $i | sed -n -e '/->translate(*/p' | sed -e 's/\(.*->translate(.\)\([a-z A-Z \d092\d039\d034]*\)\(.*\)/\2/g' | sed -e 's/\(.*\)\(\d039\)/\1/g' | sed -e 's/\(.*\)\(\d034\)/\1/g' >> give_me_your_favorite_outfile_name.txt
echo " done"
done
Unfortunately, it does not cover all the above cases, especially the Quotes within Quotes cases. As I am not a shell expert at all and need that script for a verification process, I would be very happy to get help from you guys.
Important: It has to be written in Shell. A PHP Version exists.
find /path -type f \( -name "*.php" -o -name "*.phtml" \) | while IFS= read -r -d $'\0' file
do
while read -r line
do
case "$line" in
*'$this->translate'* | *'$this->view->translate'* )
line="${line#*this*translate(}"
line="${line%%)*}"
case ${line:0:1} in
\$) s=${line:0};;
*) s=${line:1:${#line}-2};;
esac
case "$s" in
*[\"\'],* )
s=${s/\\/}
echo ${s%%[\"\'],*};;
* ) echo "$s";;
esac
esac
done < "$file"
done
This does it using sed in a Bash while loop and demonstrates another way to do the find for variety's sake:
find . -iregex ".*\.php\|.*\.phtml" |
while read f
do
sed -n '/[\"\o047]/ {s/$this->\(view->\|\)translate([\"\o047]\(.*\)[\"\o047].*)/\2/; s.\\..;p}' $f
done > outputfile.txt
Edit:
To take care of other text on the line change the sed command to this:
sed -n '/[\"\o047]/ {s/.*$this->\(view->\|\)translate([\"\o047]\(.*\)[\"\o047].*).*/\2/; s.\\..;p}' $f
(Just add a .* at the beginning and end of the search string.)

Resources