Shell command "find -name $variable" not working as expected - bash

Sorry, I am new to bash. I have a fairly simple script that is something like the below:
#!/bin/bash
grep file.txt | awk '{print $2}' | while read -r line; do
log "$line"
log "find path/to/csv -name $line"
command=$(find path/to/csv -name $line)
log "$command"
done
}
What I am trying to do is grab the second field for every line in the file.txt file, pipe it to the line variable and then use that to find any csv file in the /path/to/csv directory with a name that matches any name in file.txt. This isn't working so I have stripped it down to be as simple as I can.
When I use the $line variable in the log command, the log file brings the second field for every line as expected. However when I use the $line variable with the find command, it is not working and the log shows a blank output.
20200702-16h-12m-33s filename*.csv
20200702-16h-12m-33s find path/to/csv -name filename*.csv
20200702-16h-12m-33s
Just wondering if I need to anything to my $line variable within the find command? I have tried:
$line
"$line"
"*line*"
${line}
{$line}
Any help would be massively appreciated

Don't store the command in a variable.
That is, don't do this: command=$(find path/to/csv -name $line)
Instead just store the "find" arguments in an array and then the run find command with it.
So, in your case, it would be something like this:
args=(path/to/csv -name "$line")
find "${args[#]}"

Related

syntax error not sure what its saying or how to fix it

I am trying to write a shell script for school that searches your entire home directory for all files with the .java extension. For each such file, list the number of lines in the file along with its location (that is, its full path).
my script looks like
#!/bin/bash
total=0
for currfile in $(find ~ -name "*.java" -print)
do
total=$[total+($(wc -l $currfile| awk '{print $1}'))]
echo -n 'total=' $total
echo -e -n '\r'
done
echo 'total=' $total
when i run it from the konsole i get error
./fileQuest.sh: line 5: total+(): syntax error: operand expected (error token is ")")
I am a novice and cannot figure out what the error is telling me. Any help would be appreciated
total+()
This is the expression that's being evaluated inside of $[...]. Notice that the parentheses are empty. There should be a number there. It indicates that the $(wc | awk) bit is yielding an empty string.
total=$[total+($(wc -l $currfile| awk '{print $1}'))]
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If that part is blank then you get:
total=$[total+()]
Note that wc can handle multiple file names natively. You don't need to write your own loop. You could use find -exec to call it directly instead.
find ~ -name "*.java" -exec wc {} +

get the file name that has specific extension in shell script

I have three files in a directory that has the structure like this:
file.exe.trace, file.exe.trace.functions and file.exe.trace.netlog
I want to know how can I get file.exe as file name?
In other world I need to get file name that has the .trace extension? I should note that as you can see all the files has the .trace part.
If $FILENAME has the name, the root part can be gotten from ${FILENAME%%.trace*}
for FILENAME in *.trace; do
echo ${FILENAME%%.trace*}
done
You can also use basename:
for f in *.trace; do
basename "$f" ".trace"
done
Update: The previous won't process files with extra extensions besides .trace like .trace.functions, but the following sed will do:
sed -r 's_(.*)\.trace.*_\1_' <(ls -c1)
You can also use it in a for loop instead:
for f in *.trace*; do
sed -r 's_(.*)\.trace.*_\1_' <<< "$f"
done
Try:
for each in *exe*trace* ; do echo $each | awk -F. '{print $1"."$2}' ; done | sort | uniq

bash script prepending ? to file name

I am using the below script. When I have it echo $f as shown below, it gives the correct result:
#/bin/bash
var="\/home\/"
while read p; do
f=$(echo $p | sed "s/${var}/\\n/g")
f=${f%.sliced.bam}.fastq
echo $f
~/bin/samtools view $p | awk '{print "#"$1"\n"$10"\n+\n"$11}' > $f
./run.sh $f ${f%.fastq}
rm ${f%.sliced.bam}.fastq
done < $1
I get the output as expected
test.fastq
But the file being created by awk > $f has the name
?test.fastq
Note that the overall goal here is to run this loop on every file listed in a file with absolute paths but then write locally (which is what the sed call is for)
edit: Run directly on the command line (without variables) the samtools | awk line runs correctly.
Awk cannot possibly have anything to do with your problem. The shell is completely responsible for file redirection, so f MUST have a weird character in it.
Most likely whatever you are sending to this script has a special character in it (e.g. perhaps a UTF character, and your terminal is showing ASCII only). When you do the echo, the shell doesn't know how to display the char, and probably just shows it as whitespace, and when you send it through ls (which might be doing things like colorization) it combines in a strange way and ends up showing the ?.
Oh wait...why are you putting a newline into the filename with sed??? That is possibly your problem...try just:
sed "s/${var}//g"

Unix shell to prompt user for filename

please pardon since I am a UNIX beginner.
I wanna write a shell script that can ask user type in the filename and output the number of lines in that file, here is my code:
echo "Pls enter your filename:"
read filename
result=wc -l $filename
echo "Your file has $result lines"
However, I couldn't get it working since it complains about the identifier "filename". Could experts help?Thanks !!
That works fine, at least in bash. Well, the read works fine. However, the assignment to result should probably be:
result=$(wc -l $filename)
but, since that command outputs both the line count and the filename, you might want to change it a little to just get the line count, something like:
result=$(cat $filename | wc -l)
or:
result=$(wc -l <$filename)
The command you have:
result=wc -l $filename
will set result to the literal wc, then try to execute the -l command.
For example, the following five-line script:
#!/bin/bash
echo "Pls enter your filename:"
read filename
result=$(cat $filename | wc -l)
echo "Your file has $result lines"
will, when run and given its name as input, produce the following:
Your file has 5 lines
If you're not using bash, you need to specify which shell you are using. Different shells have different ways of doing things.
If you want to evaluate wc -l $filename , you have t do:
result=$(wc -l $filename)
Otherwise, with result=wc -l $filename, bash will assign wc to result, and interpret the next word(-l) as a command to run.
Here you go :
echo "Pls enter your filename:"
read filename
result=`wc -l $filename | tr -s " " | cut -f2 -d' '`
echo "Your file has $result lines"

Help with Bash script

I'm trying to get this script to basically read input from a file on a command line, match the user id in the file using grep and output these lines with line numbers starting from 1)...n in a new file.
so far my script looks like this
#!/bin/bash
linenum=1
grep $USER $1 |
while [ read LINE ]
do
echo $linenum ")" $LINE >> usrout
$linenum+=1
done
when i run it ./username file
i get
line 4: [: read: unary operator expected
could anyone explain the problem to me?
thanks
Just remove the [] around read line - they should be used to perform tests (file exists, string is empty etc.).
How about the following?
$ grep $USER file | cat -n >usrout
Leave off the square brackets.
while read line; do
echo $linenum ")" $LINE
done >> usrout
just use awk
awk -vu="$USER" '$0~u{print ++d") "$0}' file
or
grep $USER file |nl
or with the shell, (no need to use grep)
i=1
while read -r line
do
case "$line" in
*"$USER"*) echo $((i++)) $line >> newfile;;
esac
done <"file"
Why not just use grep with the -n (or --line-number) switch?
$ grep -n ${USERNAME} ${FILE}
The -n switch gives the line number that the match was found on in the file. From grep's man page:
-n, --line-number
Prefix each line of output with the 1-based line number
within its input file.
So, running this against the /etc/passwd file in linux for user test_user, gives:
31:test_user:x:5000:5000:Test User,,,:/home/test_user:/bin/bash
This shows that the test_user account appears on line 31 of the /etc/passwd file.
Also, instead of $foo+=1, you should write foo=$(($foo+1)).

Resources