Unix shell to prompt user for filename - shell

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"

Related

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

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[#]}"

shell script that takes a string input by the user and outputs the number of characters in it?

Please can you show me a shell script that takes a string input by the user and outputs the number of characters in it? I have tried numerous times but i can't get it right.
Use the wc function like that:
echo -n abc | wc -c
or
echo -n abc | wc -m
The -n supresses the final newline which would count as an extra character.
check manual for wc.
This should do the trick:
#!/usr/bin/env bash
echo -n "$1" | wc -c
wc is a tool to count characters, lines or bytes. -c is the option for characters.
The -n option for echo avoids the newline which would be an extra character.
Make sure to make the script executable by:
chmod +x wordcount.sh
So you will get:
user#host$ ./wordcount.sh "My String"
9

Bash - 2 arguments

How do you insert 2 arguments at the same time? so far I could only insert the $filename but
not the $Number of files I want at the same time.
this is the prompt:
"Enter the file name followed by the amount of that file you want"
grep $filename input.txt|head -n$Number;;
I am not following you. Please correct your question.
But most probably you want this:
PROMPT_TEXT='Enter the filename followed by the amount of that file you want: '
read -p "$PROMPT_TEXT" filename amount
grep -m "$amount" -- "$filename" input.txt

BASH: Strip new-line character from string (read line)

I bumped into the following problem: I'm writing a Linux bash script which does the following:
Read line from file
Strip the \n character from the end of the line just read
Execute the command that's in there
Example:
commands.txt
ls
ls -l
ls -ltra
ps as
The execution of the bash file should get the first line, and execute it, but while the \n present, the shell just outputs "command not found: ls"
That part of the script looks like this
read line
if [ -n "$line" ]; then #if not empty line
#myline=`echo -n $line | tr -d '\n'`
#myline=`echo -e $line | sed ':start /^.*$/N;s/\n//g; t start'`
myline=`echo -n $line | tr -d "\n"`
$myline #execute it
cat $fname | tail -n+2 > $fname.txt
mv $fname.txt $fname
fi
Commented you have the things I tried before asking SO. Any solutions? I'm smashing my brains for the last couple of hours over this...
I always like perl -ne 'chomp and print' , for trimming newlines. Nice and easy to remember.
e.g. ls -l | perl -ne 'chomp and print'
However
I don't think that is your problem here though. Although I'm not sure I understand how you're passing the commands in the file through to the 'read' in your shell script.
With a test script of my own like this (test.sh)
read line
if [ -n "$line" ]; then
$line
fi
and a sample input file like this (test.cmds)
ls
ls -l
ls -ltra
If I run it like this ./test.sh < test.cmds, I see the expected result, which is to run the first command 'ls' on the current working directory.
Perhaps your input file has additional non-printable characters in it ?
mine looks like this
od -c test.cmds
0000000 l s \n l s - l \n l s - l t
0000020 r a \n
0000023
From your comments below, I suspect you may have carriage returns ( "\r" ) in your input file, which is not the same thing as a newline. Is the input file originally in DOS format ? If so, then you need to convert the 2 byte DOS line ending "\r\n" to the single byte UNIX one, "\n" to achieve the expected results.
You should be able to do this by swapping the "\n" for "\r" in any of your commented out lines.
Someone already wrote a program which executes shell commands: sh file
If you really only want to execute the first line of a file: head -n 1 file |sh
If your problem is carriage-returns: tr -d '\r' <file |sh
I tried this:
read line
echo -n $line | od -x
For the input 'xxxx', I get:
0000000 7878 7878
As you can see, there is no \n at the end of the contents of the variable. I suggest to run the script with the option -x (bash -x script). This will print all commands as they are executed.
[EDIT] Your problem is that you edited commands.txt on Windows. Now, the file contains CRLF (0d0a) as line delimiters which confuses read (and ls\r is not a known command). Use dos2unix or similar to turn it into a Unix file.
You may also try to replace carriage returns with newlines only using Bash builtins:
line=$'a line\r'
line="${line//$'\r'/$'\n'}"
#line="${line/%$'\r'/$'\n'}" # replace only at line end
printf "%s" "$line" | ruby -0777 -n -e 'p $_.to_s'
you need eval command
#!/bin/bash -x
while read cmd
do
if [ "$cmd" ]
then
eval "$cmd"
fi
done
I ran it as
./script.sh < file.txt
And file.txt was:
ls
ls -l
ls -ltra
ps as
though not working for ls, I recommend having a look at find’s -print0 option
The following script works (at least for me):
#!/bin/bash
while read I ; do if [ "$I" ] ; then $I ; fi ; done ;

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