getting filenames from directory in shell script - linux

I would like to iterate a loop over all the file present in a directory using shell script. Further, I would like to display the contents from each file. I am passing directory as a command line argument.
I have a simple loop as follows:
for file in $1
do
cat $file
done
If I run
sh script.sh test
where test is a directory, I get content of first file only.
Could anyone please help me in this?

couple of alternatives:
compact modification of SMA's code:
for file in $1/*
do
[[ -f $file ]] && cat $file
done
or use find:
find $1 -type f -exec cat \{\} \;

Try something like:
for file in $1/*
do
if [[ -f $file ]] ##you could add -r to check if you have read permission for file or not
then
cat $file
fi
done

Related

linux: how to batch rename folder name and the file name under folder

I need a help to finish a script to rename a folders and .
eg: my current folders and files like below:
Gideon/gideon_lisha/Gideon_samuel/Gideon_nathan.xml
Gideon/lisha_gideon/Gideon_noah.xml
...
I want a shell command to rename them like below:
Liang/Liang_lisha/Liang_samuel/Liang_nathan.xml
Liang/lisha_Liang/Liang_noah.xml
...
I tied:
#!/bin/bash
path=$1
filename=$2
newfilename=$3
echo "We are finding '$filename' under the folder '$path'"
count=1
for i in `find $path -iname *$filename*`
do
newpath=`echo $i | sed "s/$filename/$newfilename/g"`
sudo mv "$i" "$newpath"
echo "${count}: Renaming $i to $newpath"
let count++
done
but the script will stop to:
Liang/gideon_lisha/Gideon_samuel/Gideon_nathan.xml
because it changed the folder name, so that can not find the next path. I do not know how let the script run from inner to outer instead of running outer to inner.
finally, I found out the anwser:
#!/bin/bash
path=$1
filename=$2
newfilename=$3
echo "We are finding '$filename' under the folder '$path'"
count=1
for i in `find $path -iname "*$filename*" | tac`
do
newpath=`echo $i | sed "s#\(.*\)$filename#\1$newfilename#i"`
sudo mv "$i" "$newpath"
echo "${count}: Renaming $i to $newpath"
let count++
done
really thank #susbarbatus !

Please tell me in detail about the following Script

I want to delete email "sudar.dudi#in.xyz.com" from all the files which lies in a particular directory. I used the below command after searching a lot.
The problem with this command is, it keeps on searching other than the desired directories and due to this command my other files got corrupted.
Please help me to correct this:
rrcg0/utioi
(in utioi direcotry are my files and the files are with specific names
like mpp.properties.JKH,mpp.properties.KJL,mpp.properties.KHF
likewise)
yes n|for file in $(find . -type f)
do
sed 's/sudar.dudi#in.xyz.com//g' $file > $file.tmp
mv $file.tmp $file
done
You do not need find when you know the directory.
When you want to check that an entry given by ls is a file, you can use a test:
mydir=rrcg0/utioi
for file in ${mydir}/*
do
if [ -f "${file}" ]; then
sed 's/sudar.dudi#in.xyz.com//g' $file > $file.tmp && mv $file.tmp $file
fi
done
When you only want properies files you can use
for file in ${mydir}/*properties*
I have used &&. This makes sure the mv command will only be done when the redirection succeeded.
I did not use the sed -i option, that option is not always supported.
EDIT: What about spaces in the filename?
When you might have spaces in the filename, the above script must be corrected:
sed 's/sudar.dudi#in.xyz.com//g' "$file" > "$file.tmp" && mv "$file.tmp" "$file"
Make it simpler, try using exec option of find and GNU sed option for inline editing
find <absolute dir path> -name "*" -type f -exec sed -i '/hello/d' {} \;
You can make changes to the existing files also, as then there is no need to move the file. Include -i in sed command.
Modifying codes of Walter A
mydir=rrcg0/utioi
for file in ${mydir}/*
do
if [ -f "${file}" ]; then
sed -i 's/sudar.dudi#in.xyz.com//g' $file
fi
done

shell script or linux command to recursively find all js/css file under public folder

I need help with shell script or linux command to recursively find all js/css file under public folder, then create the filename.min.jsm on the same directory of previous found but also put the filename.js inside that filename.min.jsm.
For example
public/test/a.js
public/b.js
public/test2/test3/c.js
output:
public/test/a.js
public/test/a.min.jsm -> a.js is written inside of this file
public/b.js
public/b.min.jsm -> b.js is written inside of this file
public/test2/test3/c.js
public/test2/test3/c.min.jsm c.js is written inside of this file
Here is a simple refactoring of #choroba's answer which inlines the shell script so you don't need a separate file.
find \( -name '*.js' -o -name '*.css' \) -exec sh -c '
filename=$1
path=${filename%/*}
basename=${filename##*/}
prefix=${basename%%.*}
echo "$basename" > "$path/$prefix".min.jsm
' _ {} \;
I added -o -name '*.css' and a set of parentheses for grouping the conditions, too. If you don't want to run this on CSS files, revert that change, or add a conditional to the embedded shell script snippet.
Create the following script:
#!/bin/bash
filename=$1
path=${filename%/*}
basename=${filename##*/}
prefix=${basename%%.*}
echo "$basename" > "$path/$prefix".min.jsm
Then, run
find -name '*.js' -exec /path/to/script.sh {} \;
It's not clear what you want to do with the css files, but that's left as an exercise for the reader.
You can try the following script:
#!/bin/bash
export MY_TMPDIR=$(mktemp -d)
trap 'rm -rf ${MY_TMPDIR}' EXIT
export fstyle_tmp="${MY_TMPDIR}/fstyle"
find /* -regextype posix-extended -regex '.+\.(js|css)' > "${fstyle_tmp}"
while read line; do
line2=$(echo "${line}" | sed -e 's/\.js$//' -e 's/\.css$//')
cp "${line}" "${line2}.min.jsm"
done < "${fstyle_tmp}"
exit 0
#EOF
If you dont want copy css content change:
line2=$(echo "${line}" | sed -e 's/\.js$//' -e 's/\.css$//')
cp "${line}" "${line2}.min.jsm"
For:
line2=$(echo "${line}" | sed -e 's/\.js$//' -e 's/\.css$//')
if [[ "${line}" =~ \.js$ ]]; then
cp "${line}" "${line2}.min.jsm"
else
touch "${line2}.min.jsm"
fi

Change extension of file using shell script

How to change extension of all *.dat files in a directory to *.txt.
Shell script should take the directory name as an argument. Can
take multiple directories as arguments. Print the log of command
result in appending mode with date and timestamp.
Bash can do all of the heavy lifting such as extracting the extension and tagging on a new one. For example:
for file in $1/*.dat ; do mv "$file" "${file%.*}.txt" ; done
Batch File Rename By File Extension in Unix
# change .htm files to .html
for file in *.htm ; do mv $file `echo $file | sed 's/\(.*\.\)htm/\1html/'` ; done
# change .html files to .htm
for file in *.html ; do mv $file `echo $file | sed 's/\(.*\.\)html/\1htm/'` ; done
#change .html files to .shtml
for file in *.html ; do mv $file `echo $file | sed 's/\(.*\.\)html/\1shtml/'` ; done
#change .html files to php
for file in *.html ; do mv $file `echo $file | sed 's/\(.*\.\)html/\1php/'` ; done
so ==>
# change .dat files to .txt
for file in *.dat ; do mv $file `echo $file | sed 's/\(.*\.\)dat /\1txt/'` ; done
#!/bin/bash
for d in $*; do
for f in $(ls $d/*.dat); do
echo $(date) $(mv -v $f ${f%.dat}.txt)
done
done
Output redirection should be done by the shell when running the script
Leaving out argument validity checks
Simple script:
#!/bin/bash
if [ $# -lt 2 ] then
echo "Usage `basename $0` <any number of directories space separated>"
exit 85 # exit status for wrong number of arguments.
fi
for directories
do
for files in $(ls $directories/*.dat); do
echo $(date) $(mv -v $files ${files%.dat}.txt)
done
done
The first for loop by default loops on the $# i.e. command-line arguments passed.
Follow Pben's solution, if your filename contains blank space, you should use double quotation marks to the variable like the following:
#remove the space in file name
#example file name:19-014-0100.mp3 .mp3
#result file name:19-014-0100.mp3
$ for file in *.mp3 ;
do target=`echo "$file" | sed 's/ //g'`;
echo "$target";
mv "$file" "$target";
done;
#remove the duplicate file extension in file name
#example file name:19-014-0100.mp3.mp3
#result file name:19-014-0100.mp3
$ for file in *.mp3 ;
do target=`echo "$file" | sed 's/\.mp3\.mp3$/.mp3/g'`;
echo "$target";
mv "$file" "$target";
done;
To rename (changing extention) all my html files on epub files I use this command line :
find . -name "*.html*" -exec rename -v 's/\.html$/\.epub/i' {} \;
Script, first finds the names of the given extensions.
It removes the extension from names. Then adds backslash()
for identification of terminal.
Then the 'mv' command executed.
Here the '.temp' folder is used to hide the process from user,
in GUI.
#!/bin/sh
if [ $# -ne 3 ]
then
echo "Usage: ./script folder current_extension modify_extension"
exit
fi
mkdir .temp
find $1 -name "*.$2" > .temp/output_1 && sed "s/$2//" .temp/output_1 > .temp/output_2 && sed -e "s/[ \t]/\\\ /g" .temp/output_2 > .temp/output_3
while read line
do
mv -v "$line""$2" "$line""$3"
done < .temp/output_3
rm -rf .temp
The output files are saved inside the '.temp' folder,later the '.temp' folder is removed.
The top voted answer didn't really work for me. I may have been doing something wrong. My scenario was trying to create a file with the original name, but with the date appended to it, along with changing the extension from .xslx to .csv. This is what worked for me:
csvname=`echo $xlsx |sed 's/\.xlsx//'`"-$now"`echo $xlsx | sed 's/\(.*\.\)xlsx/\.csv/'`
So, for all the .dat files in a directory (without the date addition), you could run something like this:
for i in *.dat
do mv $i `echo $i |sed 's/\.dat//'``echo $i | sed 's/\(.*\.\)dat/\.txt/'`
done
From the above, this section of code just removed the extension:
echo $i |sed 's/\.dat//'
And this section changes the .dat to .txt:
echo $i | sed 's/\(.*\.\)dat/\.txt/'
And by bumping them next to each other, it concatenates the two outputs into the filename. It's like doing this:
mv [filename][.dat] [filename] + [.txt]
Though, I did use STDOUT instead of the 'mv' command.
Following command to change file extention .c to .h
find . -depth -name "*.c" -exec sh -c 'dname=$(dirname {}) && fname=$(basename {} .c) && mv {} $dname/$fname.h' ";"
change js to cjs extension files recursively:
cd dist # where you place your .js
for file in $(find . -type f -name "*.js"); do mv "$file" "${file%.*}.cjs"; done

unable to process files of a directory in for loop in linux

i have directory that has 2 sub-directories and that again has few sub-directory and they have some files. I need to rename all the files to append an html extension to the filenames.
the directory structure looks like this
main-directory
sub-directory
sub-directory
sub-directory
file1
file2
and so on to lot of files
now i could not use something like this
for file in main-directory/*
do
if [ -f "$file" ]
then `mv "$file" "$file.html"`
fi
done
because the for loop wont use the path recursively. so i used something like this
for file in `ls -1R main-directory` // -1 for showing file and directory names separated by new lines and -R for recursive travel
do
if [ -f "$file" ]
then `mv "$file" "$file.html"`
fi
done
the above code is not able to rename files. to check whether the line
for file in `ls -1R main-directory`
is working i wrote something like this
for file in `ls -1R main-directory`
do
if [ -f "$file" ]
echo $file
done
this doesn't show anything. what can be wrong?
you can use find and look into of type file and then -exec to change all the file and then appending the .html.
find main-directory -type f -exec mv -v '{}' '{}'.html \;
In your first for loop, the mv command should not be in back-ticks.
In your second for loop, the if-statement has incorrect syntax. There is no then or fi. It should be:
for file in `ls -1R main-directory`
do
if [ -f "$file" ]
then
echo $file
fi
done
But even then, this won't work because ls -1R main-directory gives you just the file names, not the absolute paths to the file. Move your echo outside the if-statement to test:
for file in `ls -1R main-directory`
do
echo $file
done
Therefor ls -1R main-directory is not a good way to get all files in the current directory. Use find . -type f instead.
For some reason, I can never remember the find ... -exec syntax off the top of my head with the {} and the \;. Instead, I've fallen into the habit of just using a loop fed from find:
find main-directory -type f | while read file
do
mv "$file" "$file.html"
done
find outputs each file to stdout and the read file will consume one line at a time and set the contents of that line to the $file environment variable. You can then use that anywhere in the body of your loop.
I use this approach to solve lots of little problems like this where I need to loop over a bunch of output and do something useful. Because it is more versatile, I use it more than the esoteric find ... -exec {} \; approach.
Another trick is to prepend you command with echo to do a quick sanity check before doing potentially damaging things to your system:
find find main-directory -type f | while read file
do
echo mv "$file" "$file.html"
done
here is the answer to my question. people responded by 1 liners which are a neat approach but i didnt get much out of those 1 liners so here is something that i wanted
IFS=$'\n' // this is for setting field separator to new line because the default is whitespace
dir=main-directory
for file in `ls -1R main-directory | sed 's/:$//'` // -1 for showing file and directory names separated by new lines and -R for recursive travel
do
if [ -f "$dir/$file" ]
then `mv "$dir/$file" "$dir/$file.html"`
elif [ -d "$file" ]
then dir=$file
fi
done
here the sed 's/:$//' detects a : at the end of line and removes it. this was one of the things that prevented my code to run because whenever ls -1R main-directory detected a directory it appended a : at the end

Resources