cannot proceed "$ echo prog1/p*." command - linux

I am currently reading "The LPI Introductory Programme".
It says that I can try $ echo prog1/p*.c to search exact files that starts with "p" and ends with "c".
But instead of that, echo command just prints out the given in quotes, why ?

echo attempts to print file names that matches the given pattern, but if no match is found it treats pattern as text to be printed and does what it is meant for.
use ls -l prog1/p*.c instead, for listing files.
also make sure your current working directory and navigable sub directories from there.

Related

If statement comparing variable to files in list

I am using terminal emulator. I have a folder with save files in it and am trying to determine whether the entered text matches any file in the list.
I created a variable called saveFiles using the ls. Only displaying files with .save and removing it from the output:
saveFiles=$(cd "${0%/*}"/save; ls *.save* | ls *.save*; cd "${0%/*}")
echo -n ">"
read -r "name"
So $saveFiles equals:
Savegame1 savegame2 savegame3
I'm trying to make an if statement that tests wether the entered variable equals any of the files in the folder.
The following script works except when I type a letter contained at the end of the file. So if one of the files is called savegame, if I type game it comes up with a match because game.save is contained in the string.
if [[ $saveFiles = *"$name".save* ]]
then
scene=$(cat "save/$name".save)
fi
I need to find a way to test wether any of the strings in $saveFiles are equal to the entered variable $name.
To reiterate, files in folder:
Save1.save
Save2.save
...
Read `$name`
If $name matches any file in the list then load scene otherwise repeat.
I hope this isn't confusing. Please feel free to ask me to clarify further. Thank you.
Maybe I am not understanding the question correctly, but why don't you first request the file name and then query the file system with precisely that name, e.g.
read name
if [[ -f "${name}.save" ]];
echo "Found the file ${name}.save"
fi

Pick the specific file in the folder

I want pick the specific format of file among the list of files in a directory. Please find the below example.
I have a below list of files (6 files).
Set-1
1) MAG_L_NT_AA_SUM_2017_01_20.dat
2) MAG_L_NT_AA_2017_01_20.dat
Set-2
1) MAG_L_NT_BB_SUM_2017_01_20.dat
2) MAG_L_NT_BB_2017_01_20.dat
Set-3
1) MAG_L_NT_CC_SUM_2017_01_20.dat
2) MAG_L_NT_CC_2017_01_20.dat
From the above three sets I need only 3 files.
1) MAG_L_NT_AA_2017_01_20.dat
2) MAG_L_NT_BB_2017_01_20.dat
3) MAG_L_NT_CC_2017_01_20.dat
Note: There can be multiple lines of commands because i have create the script for above req. Thanks
Probably easiest and least complex solution to your problem is combining find (a tool for searching for files in a directory hierarchy) and grep (tool for printing lines that match a pattern). You also can read those tools manuals by typing man find and man grep.
Before going straight to solution we need to understand, how we will approach your problem. To find pattern in a name of file we search we will use find command with option -name:
-name pattern
Base of file name (the path with the leading directories removed) matches shell pattern pattern. The metacharacters ('*', '?', and '[]')
match a '.' at the start of the base name (this is a change in
findutils-4.2.2; see section STANDARDS CONFORMANCE below). To ignore a
directory and the files under it, use -prune; see an example in the
description of -path. Braces are not recognised as being special,
despite the fact that some shells including Bash imbue braces with a
special meaning in shell patterns. The filename matching is performed
with the use of the fnmatch(3) library function. Don't forget to
enclose the pattern in quotes in order to protect it from expansion by
the shell.
For instance, if we want to search for a file containing string 'abc' in directory called 'words_directory', we will enter following:
$ find words_directory -name "*abc*"
And if we want to search all directories in directory:
$ find words_directory/* -name "*abc*"
So first, we will need to find all files, which begin with string "MAG_L_NT_" and end with ".dat", therefore to find all matching names in /your/specified/path/ which contains many subdirectories, which could contain files that match this pattern:
$ find /your/specified/path/* -name "MAG_L_NT_*.dat"
However this prints all found filenames, but we still get names containing "SUM" string, there comes in grep. To exclude names containing unwanted string we will use option -v:
-v, --invert-match
Invert the sense of matching, to select non-matching lines. (-v is
specified by POSIX .)
To use grep to filter out first commands output we will use pipe () |:
The standard shell syntax for pipelines is to list multiple commands,
separated by vertical bars ("pipes" in common Unix verbiage). For
example, to list files in the current directory (ls), retain only the
lines of ls output containing the string "key" (grep), and view the
result in a scrolling page (less), a user types the following into the
command line of a terminal:
ls -l | grep key | less
"ls -l" produces a process, the output (stdout) of which is piped to
the input (stdin) of the process for "grep key"; and likewise for the
process for "less". Each process takes input from the previous process
and produces output for the next process via standard streams. Each
"|" tells the shell to connect the standard output of the command on
the left to the standard input of the command on the right by an
inter-process communication mechanism called an (anonymous) pipe,
implemented in the operating system. Pipes are unidirectional; data
flows through the pipeline from left to right.
process1 | process2 | process3
After you got acquainted to mentioned commands and options which will be used to achieve your goal, you are ready for solution:
$ find /your/specified/path/* -name "MAG_L_NT_*.dat" | grep -v "SUM"
This command will produce output of all names which begin "MAG_L_NT_" and end with ".dat". grep -v will use first command output as input and remove all lines containing "SUM" string.

Pass content from .txt file as argument for bash script?

I need to "Write a script to add users to your system in which the names of the users are given to script as an argument n (in?, spell error by professor) a text file of the format
Last_Name First_Name Middle_Initial Group
(rest of instructions FYI) Your script should create unique user names of up to 8 characters, and generate
random passwords for the users. The users should be assigned home directories
depending on the group they are in. You can assume that the users will belong to
Management (“mgmt”), Employee (“empl”) or Temporary (“temp”) and that their
respective directories are under these group names in /home. For e.g., if John Doe is
in “mgmt.”, and his user name is jdoe1234, then his home directory should be in
/home/mgmt/jdoe1234. Lock the home directories such that no one else has
permissions to the home directories than the users themselves.
Your script should generate a file called users.txt that contains the following columns:
Last Name First Name UID Password
which can be used to distribute the user names and passwords to the users.
The first part (not in italics) is what confuses me. If I understand his wording correctly, he wants me to take text from a separate .txt file and use it as the arguments for my script? With the idea of
./file.sh arg1 arg2 arg3 arg4
except those args are going to be the first four words in the .txt file? Say, if the .txt file contains "Doe John A empl", then it would be like typing
./file.sh arg1 arg2 arg3 arg4
Here's my attempt so far (I've actually tried other things but this is what I have on screen right now, sort of what I started out with):
#!/bin/bash
echo "$(cat file.txt)"
lname=$(echo $1|head -c 3)//to make username use first 3 letters of last name
fname=$(echo $2|head -c 1)//to make username use first letter of first name
mname=$3
group=$4
echo "$lname$fname$mname$group"
As of right now, anything below the first line doesn't do anything. I got the first line from command line arguments from a file content and I used it because I thought it would let me use the content from a .txt file as arguments but it's clearly not doing that. It's just outputting the content of it, not using letting me using each word as an argument. Not sure what to do. Any help? I thought this wasn't going to be very difficult as I started writing the script assuming the user would provide the arguments but I reread the first part of the instructions and assume he wants them to be taken from a separate .txt file.
$(command) returns the output of the command. If you do $(cat some_file) it will return the text of the file. You can use it to give the content of a file as an argument doing:
cmd1 $(cat args_file)
So when you use echo $(cat file.txt), you get the same output as if you were using cat file.txt because cat sends the content of the file to echo which displays it to the standard output.
$n means argument n passed to the script ($0 being the name of the script). Here you simply have to provide one argument, the name of the file. So $2, $3 and $4 will not contain anything.
So, from the file you can only get a string with the names with $names=$(cat $1). In order to get each field separately, you can use cut:
lname=$(cut -d \ -f 1 $1)
fname=$(cut -d \ -f 2 $1)
mname=$(cut -d \ -f 3 $1)
group=$(cut -d \ -f 4 $1)
NOTES:
The symbol for comments in shell is # NOT //.
head displays the first lines of a file, head -c the first bytes. It does not cut the file.
What I understood as the problem is that:
Firstly: You want to pass the contents of a text file as an input/argument to a shell script.
There could be other ways, but I suggest the following:
./YourScriptFile.sh $(cat YourInputFile.txt)
Secondly: You want to use its contents.
I would suggest to use the following inside your script file:
$1, $3, $4, ..., $n
to access the:
1st, 2nd, 3rd, ..., nth
tokens from the input file (irrespective of new lines).
Finally: You want to make username use first 3 letters of last name or in other words you want to extract characters from a string.
Once you have tokens it's just simple. I would suggest the following:
FirstTwoChars_of_FirstToken=${1:0:2}
FirstTwoChars_of_SeventhToken=${7:0:2}
Or
LastTwoChars_of_FirstToken=${1:7:9}
# if the first token is "FirstName" it would return you "me"
Hope this would help you to improve your code.
As a footnote: Your code will become: (# is used for comments here)
#!/bin/bash
lname=$(1:0:3) #to make username use first 3 letters of last name
fname=$(2:0:1) #to make username use first letter of first name
mname=$3
group=$4
echo "$lname$fname$mname$group"
Now you will have to execute your shell script as mentioned above.

storing output of ls command consisting of files with spaces in their names

I want to store output of ls command in my bash script in a variable and use each file name in a loop, but for example one file in the directory has name "Hello world", when I do variable=$(ls) "Hello" and "world" end up as two separate entries, and when I try to do
for i in $variable
do
mv $i ~
done
it shows error that files "Hello" and "world" doesn't exist.
Is there any way I can access all files in current directory and run some command even if the files have space(s) in their names.
If you must, dirfiles=(/path/of/interest/*).
And accept the admonition against parsing the output of ls!
I understand you are new to this and I'd like to help. But it isn't easy for me (us?) to provide you with an answer that would be of much help to you by the way you've stated your question.
Based on what I hear so far, you don't seem to have a basic understanding on how parameter expansions work in the shell. The following two links will be useful to you:
Matching Pathnames, Parameters
Now, if your task at hand is to operate on files meeting certain criteria then find(1) will likely to do the job.
Say it with me: don't parse the output of ls! For more information, see this post on Unix.SE.
A better way of doing this is:
for i in *
do
mv -- "$i" ~
done
or simply
mv -- * ~

Using wildcards to exclude files with a certain suffix

I am experimenting with wildcards in bash and tried to list all the files that start with "xyz" but does not end with ".TXT" but getting incorrect results.
Here is the command that I tried:
$ ls -l xyz*[!\.TXT]
It is not listing the files with names "xyz" and "xyzTXT" that I have in my directory. However, it lists "xyz1", "xyz123".
It seems like adding [!\.TXT] after "xyz*" made the shell look for something that start with "xyz" and has at least one character after it.
Any ideas why it is happening and how to correct this command? I know it can be achieved using other commands but I am especially interested in knowing why it is failing and if it can done just using wildcards.
These commands will do what you want
shopt -s extglob
ls -l xyz!(*.TXT)
shopt -u extglob
The reason why your command doesn't work is beacause xyz*[!\.TXT] which is equivalent to xyz*[!\.TX] means xyz followed by any sequence of character (*) and finally a character in set {!,\,.,T,X} so matches 'xyzwhateveryouwant!' 'xyzwhateveryouwant\' 'xyzwhateveryouwant.' 'xyzwhateveryouwantT' 'xyzwhateveryouwantX'
EDIT: where whateveryouwant does not contain any of !\.TX
I don't think this is doable with only wildcards.
Your command isn't working because it means:
Match everything that has xyz followed by whatever you want and it must not end with sequent character: \, .,T and X. The second T doesn't count as far as what you have inside [] is read as a family of character and not as a string as you thought.
You don't either need to 'escape' . as long as it has no special meaning inside a wildcard.
At least, this is my knowledge of wildcards.

Resources