Linux: Loop using foldername when finding file - linux

I'm currently trying to use the following linux script to loop through folders and perform calculations using a function:
for f in s*
do
echo "You are in the following folder - $s"
cd $s
# FUNCTION SHOULD BE HERE
cd /C/Users/Eric/Desktop/Files
done
The problem: How can I use the foldername to find the correct file? For example, the foldername is scan1 and I want to use the file called gaf_scan1_recording_mic.nii for the function.
Thanks a lot,
Eric

In most cases, $var and ${var} are the same (the braces are only needed for ambiguity in the expressions):
var=test
echo $var
# test
echo ${var}
# test
echo $varworks
# prints nothing (there is no variable 'varworks')
echo ${var}works
# testworks
You can use the folder name like this (gaf_${f}_recording_mic.nii):
for f in *; do
# Check if $f is a directory
if [[ -d $f ]]; then
echo "You are in the following folder - $f"
cd $f
# The filename to use for your function
do_stuff gaf_${f}_recording_mic.nii
fi
done

Related

How can I remove the extension of specific files in a directory?

I want to remove the extension of specific files with a given extension.
So for instance, in a directory foobar, we have foo.txt, bar.txt foobar.jpg.
Additionally, the extension that I've put in to be removed is txt
After calling the program, my output should be foo bar foobar.jpg
Here is my code so far:
#!/bin/bash
echo "Enter an extension"
read extension
echo "Enter a directory"
read directory
for file in "$directory"/*; do //
if [[ $file == *.txt ]]
then
echo "${file%.*}"
else
echo "$file"
fi
done
However when I run this on a given directory, nothing shows up.
I'm assuming that there is a problem with how I referred to the directory ( in the line where I placed a //) and I've tried to research on how to solve it but to no avail.
What am I doing wrong?
If files do exist in a valid directory you've entered then they should show up — with one exception. If you are using ~/ (shorthand home directory) then it will be treated as plain text in your for loop. The read variable should be substituted into another variable so the for loop can treat it as a directory (absolute paths should work normally as well).
#!/bin/bash
echo "Enter an extension"
read -r extension
echo "Enter a directory"
read -r directory
dir="${directory/#\~/$HOME}"
for file in "$dir"/*; do
if [[ $file == *."$extension" ]]
then
echo "${file%.*}"
else
echo "$file"
fi
done
You can simplify your for-loop:
for file in "$directory"/*; do
echo "${f%.$extension}";
done
The % instructions removes only matching characters. If nothing matches, the original string (here f) is returned.
When you write bash scripts it's more common to pass arguments to your script via command line arguments rather than by reading it from standard input via read program.
Passing arguments via command line:
#!/bin/bash
# $# - a bash variable which holds a number of arguments passed
# to script via command line arguments
# $0 holds the name of the script
if [[ $# -ne 2 ]]; then # checks if exactly 2 arguments were passed to script
echo "Usage: $0 EXTENSION DIRECTORY"
exit -1;
fi
echo $1; # first argument passed to script
echo $2; # second arugment passed to script
This approach is more efficient because a subprocess is spawn for read command to run and there is no subprocess spawn for reading command line arguments.
There is no need to manually loop through directory, you can use find command to find all files with given extension within given directory.
find /path/to/my/dir -name '*.txt'
find $DIRECTORY -name "*.$EXTENSION"
# note that single quotes in this context would prevent $EXTENSION
# variable to be resolved, so double quotes are used " "
# find searches for files inside $DIRECTORY and searches for files
# matching pattern '*.$EXTENSION'
Note that to avoid bash filename expansion sometimes it is required to wrap actual pattern in single quotes ' ' or double quotes " ". See Bash Filename Expansion
So now your script can look like this:
#!/bin/bash
if [[ $# -ne 2 ]]; then
echo "Usage: $0 EXTENSION DIRECTORY"
exit -1;
fi
$EXTENSION = $1 # for better readability
$DIRECTORY = $2
for file in `find $DIRECTORY -name "*.$EXTENSION"`; do
mv $file ${file%.$EXTENSION}
done
Construct ${file%.$EXTENSION} is called Shell Parameter Expansion it searches for occurrence of .$EXTENSION inside file variable and deletes it.
Notice that in the script it is easy to pass extension as directory and vice versa.
We can check if second argument is in fact directory, we can use following construction:
if ! [[ -d $DIRECTORY ]]; then
echo $DIRECTORY is not a dir
exit -1
fi
This way we can exit from the script earlier with more readable error.
To sum up entire script could look like this:
#!/bin/bash
if [[ $# -ne 2 ]]; then
echo "Usage: $0 EXTENSION DIRECTORY"
exit -1;
fi
EXTENSION=$1 # for better readability
DIRECTORY=$2
if ! [[ -d $DIRECTORY ]]; then
echo $DIRECTORY is not a directory.
exit -1
fi
for file in `find $DIRECTORY -name "*.$EXTENSION"`; do
mv $file ${file%.$EXTENSION}
done
Example usage:
$ ./my-script.sh txt /path/to/directory/with/files

bash scripts list files in a directory

I'm writing a script that takes an argument which is a directory .
i want to be able to construct list/array with all the files that have a certain extension in that directory and cut their extension .
For example if i have directory containing :
aaa.xx
bbb.yy
ccc.xx
and im searching for *.xx .
my list/array would be : aaa ccc.
I'm trying to use the code in this thread example the accepted answer .
set tests_list=[]
for f in $1/*.bpt
do
echo $f
if [[ ! -f "$f" ]]
then
continue
fi
set tmp=echo $f | cut -d"." -f1
#echo $tmp
tests_list+=$tmp
done
echo ${tests_list[#]}
if i run this script i get that the loop only executes once with $f is tests_list=[]/*.bpt which is weird since $f should be a file name in that directory , and echo empty string.
i validated that i'm in the correct directory and that the argument directory have files with .bpt extensions .
This should work for you:
for file in *.xx ; do echo "${file%.*}" ; done
To expand this to a script that takes an argument as a directory:
#!/bin/bash
dir="$1"
ext='xx'
for file in "$dir"/*."$ext"
do
echo "${file%.*}"
done
edit: switched ls with for - thanks #tripleee for the correction.
filear=($(find path/ -name "*\.xx"))
filears=()
for f in ${filear[#]}; do filears[${#filears[#]}]=${f%\.*}; done

Batch Renaming multiple files with different extensions Linux Script?

I would like to write a linux script that will move or copy all files with the same filename (but different extensions) to a new filename for all those files, while maintaining their different extensions. In other words:
if I start with a directory listing:
file1.txt, file1.jpg, file1.doc, file12.txt, file12.jpg, file12.doc
I would like to write a script to change all the filenames without changing the extensions. For the same example, choosing file2 as the new filename the result would be:
file2.txt, file2.jpg and file2.doc, file12.txt, file12.jpg, file12.doc
So the files whose filename do not match the current criteria will not be changed.
Best wishes,
George
Note: If there's file1.doc in variable i, expression ${i##*.} extracts extension i.e. doc in this case.
One line solution:
for i in file1.*; do mv "$i" "file2.${i##*.}"; done
Script:
#!/bin/sh
# first argument - basename of files to be moved
# second arguments - basename of destination files
if [ $# -ne 2 ]; then
echo "Two arguments required."
exit;
fi
for i in $1.*; do
if [ -e "$i" ]; then
mv "$i" "$2.${i##*.}"
echo "$i to $2.${i##*.}";
fi
done
The util-linux-ng package (most of linux flavours have it installed by default) has the command 'rename'. See man rename for use instructions. Using it your task can be done simply as that rename file1 file2 file1.*
To handle input files whose basenames contain special characters, I would modify plesiv's script to the following:
if [ $# -ne 2 ]; then
echo "Two arguments required."
exit;
fi
for i in "$1".*; do
if [ -e "$i" ]; then
mv "$i" "$2.${i##*.}"
echo "$i to $2.${i##*.}";
fi
done
Note the extra quotes around $1.

Linux file deletion error

Every time I run this code I get the error File or directory doesn't exist. Why?
read -p "Enter the filename/path of the file you wish to delete : " filename
echo "Do you want to delete this file"
echo "Y/N"
read ans
case "$ans" in
Y) "`readlink -f $filename`" >>~/TAM/store & mv $filename ~/TAM/dustbin
echo "File moved" ;;
N) "File Not deleted" ;;
esac
When I enter the file name/directory exactly and triple check its right I still get this error, but the readlink part works.
Paraphrasing/summarizing/extending my answer for a similar question:
I doubt you really meant to use & instead of && in your script.
"File Not deleted" is not a valid command on any Linux system that I have used. Perhaps you are missing an echo there?
You have to fix your variable quotation. If the filename variable contains whitespace, then $filename is expanded by the shell into more than one arguments. You need to enclose it into double quotes:
mv "$filename" ~/TAM/dustbin
I do not see your script creating the ~/TAM/ directory anywhere...
You are missing an echo and one &&.
Use echo "`command`" to pipe the result string of commands. Alternatively, you may directly use the command without backticks and quotes, (not storing the result in a string), in which case you do not need an echo because the command will pipe its result to the next command.
The single & will run the preceding command in the background (async.). To check for return values and conditionally execute you need && and ||.
Here is a complete solution/example (incl. some more logging):
# modified example not messing the $HOME dir.
# should be save to run in a separate dir
touch testfile #create file for testing
read -p "Enter the filename/path of the file you wish to delete : " filename
echo "Do you want to delete this file: $filename"
echo "Y/N"
read ans
touch movedfiles #create a file to store the moved files
[ -d _trash ] || mkdir _trash #create a dustbin if not already there
case "$ans" in
Y) readlink -f "$filename" >> movedfiles && echo "File name stored" &&
mv "$filename" _trash && echo "File moved" ;;
N) echo "File Not deleted" ;;
esac
cat movedfiles #display all moved files

Editing every file in a directory after opening it bash

Looking around I didn't see exactly what I was looking for. Some similar stuff, but for some reason what I tried so far hasn't worked.
My main goals:
run script in my current directory
open the picture to see what it is
rename the picture i just viewed
repeat the process without running the script again
These were the sources I attempted to follow:
Bash Shell Loop Over Set of Files
Bash loop through directory and rename every file
How to do something to every file in a directory using bash?
==================================================================================
echo "Rename pictures. Path"
read path
for f in $path
do
eog $path
echo "new name"
read newname
mv $path $newname
cat $f
done
You should pass the script an argument rather than trying to make it interactive. You also have numerous quoting problems. Try something like this instead (untested):
#!/usr/bin/env bash
moveFile() {
local newName=
until [[ $newName ]]; do
printf '%s ' 'new name:'
read -er newName # -e implies Bash with readline
echo
done
mv -i "$1" "${1%/*}/${newName}"
}
if [[ ! -d $1 ]]; then
echo 'Must specify a path' >&2
exit 1
fi
for f in "$1"/*; do
eog "$f"
moveFile "$f"
done
You might want to try something like this:
for f in $*; do
eog $f
echo "new name:"
read newname
mv $f $newname
done
If you name the script, say, rename.sh, you can call
./rename.sh *gif
to review all files with extention 'gif'.
Using find command allows you to search for image files in the specified directory recursively.
echo -n "Rename pictures. Input image directory: "
read path
for f in `find $path -type f`
do
eog $f
echo -n "Enter new name: "
read newname
mv $f $newname
echo "Renamed $f to $newname."
done

Resources