rename file names work in command prompt but not in bash script - bash

I'm trying to rename commands in a bash script. If I run for example:
echo /home/scientist/mySalesData/campaignData_1482386214.24417.csv | sed 's/\(.*\)\(_.*\)/mv \"&" \"\1.csv\"/' | bash
It works fine and gives me campaignData.csv in the directory /home/scientist/mySalesData/ .
However, if I put this in a bash script as follows:
for f in /home/scientist/SalesData/*; do
if [ -f "$f" ];
cp "$f" /home/scientist/SalesForce/SalesData/Backups/
echo $f$ | sed 's/\(.*\)\(_.*\)/mv \"&" \"\1.csv\"/' | bash |
fi
done
I get:
mv: cannot stat '/home/scientist/SalesData/campaignData_1482386214.24417.csv$': No such file or directory
Any help would be much appreciated!

cd "$srcdir"
for f in *; do
if [ -f "$f" ]; then
cp "./$f" "$dstdir/${f%_*}.csv"
fi
done
The % is the strip shortest suffix pattern operator.

You have a trailing $ here:
echo $f$
remove that (and quote the expansion):
echo "$f"
You could use here string too:
sed ... <<<"$f"

Related

rename all the files in the current directory whose name conatains upper-case into all lower case

Iam trying a shell script which will rename all the files in the current directory whose name contains upper-case characters into all lower case. For example, if the directory contains a file whose name is CoUnt.c, it should be renamed to count.c.
for f in *;
do
if [ -f "$f" ]; then
tr 'A-Z' 'a-z'
fi
done
but it is not working.
is there is any better solution for this?
You are not passing any data into the tr program, and you are not capturing any output either.
If you are using sh:
for f in *[A-Z]*
do
if [ -f "$f" ]; then
new_name=$(echo "$f"|tr 'A-Z' 'a-z')
mv "$f" "$new_name"
fi
done
Note the indentation - it makes code easier to read.
If you are using bash there is no need to use an external program like tr, you can use bash expansion:
for f in *[A-Z]*
do
if [[ -f $f ]]; then
new_name=${f,,*}
mv "$f" "$new_name"
fi
done
The problem is tr accepts values from stdin. So in order to translate upper to lower in each filename, you could do something like:
#!/bin/sh
for f in *
do
[ -f "$f" ] || continue
flc=$(echo "$f" | tr 'A-Z' 'a-z') ## form lower-case name
[ "$f" != "$flc" ] && echo mv "$f" "$flc"
done
(note: remove the echo before mv to actually move the files after you are satisfied with the operation)
Since I am unable to add comment posting here,
Used sed and it works for me
#!/bin/bash
for i in *
do
if [ -f $i ]
then
kar=$(echo "$i" | sed 's/.*/ \L&/')
mv "$i" "$kar"
done
The following code works fine.
for f in *
do
if [ -f $f ]; then
echo "$f" | tr 'A-Z' 'a-z' >/dev/null
fi
done
I would recommend rename because it is simple, efficient and also will check for clashes when two different files resolve to the same result:
You can use it with a Perl regex:
rename 'y/A-Z/a-z/' *
Documentation and examples available here.

What is wrong with my list naming code?

I would like to change the file name from Sub****_Ses1 to HU_TT_12_****_UU;
(**** numbered from 0001 to 1600)
I did the below
#!/bin/sh
#Change file name
Subj_id=/Users/dave/biomark/dat
cd Subj_id
for abcd in Sub****_Ses1; do
mv Sub$a$b$c$d_Ses1 HU_TT_12_$a$b$c$d_UU;
done
for and wildcards don't work like this. Use cut to extract the number.
$ touch Sub000{1,2,3,4}_Ses1
$ for f in Sub????_Ses1
do
abcd=$(echo $f | cut -b4-7)
mv $f HU_TT_12_${abcd}_UU
done
$ ls HU_TT_12_000*
HU_TT_12_0001_UU HU_TT_12_0002_UU HU_TT_12_0003_UU HU_TT_12_0004_UU
You can use sed and mv
#!/bin/bash
set -x
Subj_id=/Users/dave/biomark/dat
cd $Subj_id
for i in Sub*_Ses1 ; do
#echo $i|sed -r 's/^.*\([[:digit:]]{4}\).*/HU_TT_12_\1_UU/'
mv $i $(echo $i|sed -rn 's/^.*([[:digit:]]{4}).*/HU_TT_12_\1_UU/ p')
done

Cannot escape path in bash file

I'm trying to run some command with looping through all files in a directory. The code is:
#!/bin/bash
shopt -s nullglob
INPUT_DIR=$1
OUTPUT_DIR=$2
: ${INPUT_DIR:="."}
: ${OUTPUT_DIR:="."}
files="$INPUT_DIR/*.ttf"
for file in $files
do
base_file=${file##*/}
output="$OUTPUT_DIR/${base_file%.*}.woff"
ttf2woff "$file" "$output" || exit 1
done
I'd expect the double qoutes around $INPUT_DIR/*.ttf would do the magic but apparently it's not:
$> ttf2woff_multi "/Users/ozan/Dropbox/Graphic Library/Google Fonts/fonts-master/ofl/raleway"
Can't open input file (/Users/ozan/Dropbox/Graphic)
and when I print out $FILES I get: /Users/ozan/Dropbox/Graphic Library/Google
What am I missing here?
Edit: files="$INPUT_DIR"/*.ttf instead of files="$INPUT_DIR/*.ttf" doesn't work either...
In addition to the array solution, (which is a good solution), you can also make use of read with process substitution:
INPUT_DIR=${1:=.}
OUTPUT_DIR=${2:=.}
[ -d "$INPUT_DIR" -a -d "$OUTPUT_DIR" ] || {
printf "error: invalid directory specified (INPUT_DIR or OUTPUT_DIR)\n"
exit 1
}
while IFS= read -r file; do
base_file=${file##*/}
output="$OUTPUT_DIR/${base_file%.*}.woff"
ttf2woff "$file" "$output" || exit 1
done < <(find "$INPUT_DIR" -type f -iname "*.ttf")
Since you want to loop through a list of files, better store them in an array:
files=("$INPUT_DIR"/*.ttf)
for file in "${files[#]}"
do
base_file=${file##*/}
output="$OUTPUT_DIR/${base_file%.*}.woff"
ttf2woff "$file" "$output" || exit 1
done
Note you were saying "$INPUT_DIR/*.ttf" whereas I am suggesting "$INPUT_DIR"/*.ttf. This is to allow the globbing to behave as intended and expand properly.
The key point here, as Cyrus mentions in comments, is the fact of not quoting, since they prevent globbing.
See an example with some files.
$ ls f*
f1 f2 f3
Store with double quotes... it just matches the string itself:
$ files=("f*")
$ for f in "${files[#]}"; do echo "$f"; done
f*
See how it is expanded if we do not quote:
$ files=(f*)
$ for f in "${files[#]}"; do echo "$f"; done
f1
f2
f3

Renaming Multiples Files To delete first portion of name

I have a list of files like so :
10_I_am_here_001.jpg
20_I_am_here_003.jpg
30_I_am_here_008.jpg
40_I_am_here_004.jpg
50_I_am_here_009.jpg
60_I_am_here_002.jpg
70_I_am_here_005.jpg
80_I_am_here_006.jpg
How can I rename all the files in a directory, so that I can drop ^[0-9]+_ from the filename ?
Thank you
Using pure BASH:
s='10_I_am_here_001.jpg'
echo "${s#[0-9]*_}"
I_am_here_001.jpg
You can then write a simple for loop in that directory like this:
for s in *; do
f="${s#[0-9]*_}" && mv "$s" "$f"
done
Using rename :
rename 's/^[0-9]+_//' *
Here's another bash idea based on files ending .jpg as shown above or whatever>
VonBell
#!/bin/bash
ls *.jpg |\
while read FileName
do
NewName="`echo $FileName | cut -f2- -d "_"`"
mv $FileName $NewName
done
With bash extended globbing
shopt -s extglob
for f in *
do
[[ $f == +([0-9])_*.jpg ]] && mv "$f" "${f#+([0-9])_}"
done

Removing final bash script argument

I'm trying to write a script that searches a directory for files and greps for a pattern. Something similar to the below except the find expression is much more complicated (excludes particular directories and files).
#!/bin/bash
if [ -d "${!#}" ]
then
path=${!#}
else
path="."
fi
find $path -print0 | xargs -0 grep "$#"
Obviously, the above doesn't work because "$#" still contains the path. I've tried variants of building up an argument list by iterating over all the arguments to exclude path such as
args=${#%$path}
find $path -print0 | xargs -0 grep "$path"
or
whitespace="[[:space:]]"
args=""
for i in "${#%$path}"
do
# handle the NULL case
if [ ! "$i" ]
then
continue
# quote any arguments containing white-space
elif [[ $i =~ $whitespace ]]
then
args="$args \"$i\""
else
args="$args $i"
fi
done
find $path -print0 | xargs -0 grep --color "$args"
but these fail with quoted input. For example,
# ./find.sh -i "some quoted string"
grep: quoted: No such file or directory
grep: string: No such file or directory
Note that if $# doesn't contain the path, the first script does do what I want.
EDIT : Thanks for the great solutions! I went with a combination of the answers:
#!/bin/bash
path="."
end=$#
if [ -d "${!#}" ]
then
path="${!#}"
end=$((end - 1))
fi
find "$path" -print0 | xargs -0 grep "${#:1:$end}"
EDIT:
Original was just slightly off. No removal is to be done if the last argument is not a directory.
#!/bin/bash
if [ -d "${!#}" ]
then
path="${!#}"
remove=1
else
path="."
remove=0
fi
find "$path" -print0 | xargs -0 grep "${#:1:$(($#-remove))}"

Resources