What I have to to is edit a script given to me that will check if the user has write permission for a file named journal-file in the user's home directory. The script should take appropriate actions if journal-file exists and the user does not have write permission to the file.
Here is what I have written so far:
if [ -w $HOME/journal-file ]
then
file=$HOME/journal-file
date >> file
echo -n "Enter name of person or group: "
read name
echo "$name" >> $file
echo >> $file
cat >> $file
echo "--------------------------------" >> $file
echo >> $file
exit 1
else
echo "You do not have write permission."
exit 1
fi
When I run the script it prompt me to input the name of the person/group, but after I press enter nothing happens. It just sits there allowing me to continue inputting stuff and doesn't continue past that part. Why is it doing this?
The statement:
cat >>$file
will read from standard input and write to the file. That means it will wait until you indicate end of file with something like CTRL-D. It's really no different from just typing cat at a command line and seeing that nothing happens until you enter something and it waits until you indicate end of file.
If you're trying to append another file to the output file, you need to specify its name, such as cat $HOME/myfile.txt >>$file.
If you're trying to get a blank line in there, use echo rather than cat, such as echo >>$file.
You also have a couple of other problems, the first being:
date >> file
since that will try to create a file called file (in your working directory). Use $file instead.
The second is the exit code of 1 in the case where what you're trying to do has succeeded. That may not be a problem now but someone using this at a later date may wonder why it seems to indicate failure always.
To be honest, I'm not really a big fan of the if ... then return else ... construct. I prefer fail-fast with less indentation and better grouping of output redirection, such as:
file=${HOME}/journal-file
if [[ ! -w ${file} ]] ; then
echo "You do not have write permission."
exit 1
fi
echo -n "Enter name of person or group: "
read name
(
date
echo "$name"
echo
echo "--------------------------------"
echo
) >>${file}
I believe that's far more readable and maintainable.
It's this line
cat >> $file
cat is concatenating input from standard input (ie whatever you type) to $file
I think the part
cat >> $file
copies everything from stdin to the file. Maybe if you hid Ctrl+D (end of file) the script can continue.
1) You better check first whether the file exists or not:
[[ -e $HOME/journal-file ]] || \
{ echo "$HOME/journal-file does not exist"; exit 1 }
2) You gotta change "cat >> $file" for whatever you want to do with the file. This is the command that is blocking the execution of the script.
Related
I copied that code to make a THM exercise, I understand it and it does his job that's passing names from a wordlist ($2) to steghide to try to crack the image ($1), and it works, but the problem is that it doesn't show correctly the correct password, it just stops in the word before it, and if you click enter it keeps going, I would like to just stop when it finds it and show me the password, here's the code:
for word in $(cat $2); do
steghide extract -sf $1 -p $word &> /dev/null
if [ $? == 0 ]; then
echo
echo "[!] PWD FOUND - $word [!]"
break
else
echo "NOPE - $word"
fi
done
Steghide was asking me if I wanted to re-write the output file as I already did this process once, so that was the only problem, my script wasn't expecting another input request from steghide.
I am trying to create my first bash script:
echo "What file are we looking for: "
read FILE
while [ 1 ]
do
ls -lah | grep $FILE
sleep 1;
clear
# Some way to detect user input
if [ user-input ]
then
echo "Input found"
exit 1;
fi
done
Is there a way to look for user input without pausing the program? When I used read input before the if statement, the program stopped until input was...inputted.... The program is supposed to continuously output the file I am look using ls and clear so I can monitor the size as it grows, but when the user inputs any key stroke the program exits.
Like I said this is my first bash script, I do know python pretty well and understand 'coding' but not bash.
Thanks
check Bash input without pausing the script?, seems like a duplicate.
from that link:
read -t0 can be used to probe for input if your process is structured as a loop
#!/bin/bash
a='\|/-'
spin()
{
sleep 0.3
a="${a:1}${a:0:1}"
echo -n $'\e'7$'\r'"${a:1:1}"$'\e'8
}
echo 'try these /|\- , dbpq , |)>)|(<( , =>-<'
echo -n " enter a pattern to spin:"
while true
do
spin
if read -t0
then
read a
echo -n " using $a enter a new pattern:"
fi
done
else you could run one command in the background while promptiong for input in the foreground. etc...
I've seen several answers on SO about how to append to a file if it exists and create a new file if it doesn't (echo "hello" >> file.txt) or overwrite a file if it exists and create one if it doesn't (echo "hello" > file.txt).
But how do I make sure that echo "hello" only works and appends to the file if it already exists and raises an error if it doesn't?
EDIT: Right now, I'm already checking for the file using [ -f file.txt ]. I was wondering if there's a way in which I could simply use echo.
Assuming the file is either nonexistent or both readable and writable, you can try to open it for reading first to determine whether it exists or not, e.g.:
command 3<file 3<&- >>file
3<&- may be omitted in most cases as it's unexpected for a program to start reading from file descriptor 3 without redirecting it first.
Proof of concept:
$ echo hello 3<file 3<&- >>file
bash: file: No such file or directory
$ ls file
ls: cannot access 'file': No such file or directory
$ touch file
$ echo hello 3<file 3<&- >>file
$ cat file
hello
$
This works because redirections are processed from left to right, and a redirection error causes the execution of a command to halt. So if file doesn't exist (or is not readable), 3<file fails, the shell prints an error message and stops processing this command. Otherwise, 3<&- closes the descriptor (3) associated with file in previous step, >>file reopens file for appending and redirects standard output to it.
I think a simple if as proposed in the other answers would be best. However, here are some more exotic solutions:
Using dd
dd can do the check and redirection in one step
echo hello | dd conv=nocreat of=file.txt
Note that dd prints statistics to stderr. You can silence them by appending 2> /dev/null but then the warning file does not exist goes missing too.
Using a custom Function
When you do these kind of redirections very often, then a reusable function would be appropriate. Some examples:
Run echo and redirect only if the file exists. Otherwise, raise the syntax error -bash: $(...): ambiguous redirect.
ifExists() { [ -f "$1" ] && printf %s "$1"; }
echo hello >> "$(ifExists file.txt)"
Always run echo, but print a warning and discard the output if the file does not exist.
ifExists() {
if [ -f "$1" ]; then
printf %s "$1"
else
echo "File $1 does not exist. Discarding output." >&2
printf /dev/null
fi
}
echo hello >> "$(ifExists file.txt)"
Please note that ifExists cannot handle all file names. If you deal with very unusual filenames ending with newlines, then the subshell $( ...) will remove those trailing newlines and the resulting file will be different from the one specified. To solve this problem you have to use a pipe.
Always run echo, but print a warning and discard the output if the file does not exist.
appendIfExists() {
if [ -f "$1" ]; then
cat >> "$1"
else
echo "File $1 does not exist. Discarding output." >&2
return 1
fi
}
echo hello | appendIfExists file.txt
Just check:
if [ -f file.txt ]; then
echo "hello" >> file.txt
else
echo "No file.txt" >&2
exit 1
fi
There's no way in bash to alter how >> works; it will always (try to) create a file if it doesn't already exist.
For example:
if [ -f "filename" ]; then
echo "hello" >>filename
fi
I need to add new lines with specific information to one or multiple files at the same time.
I tried to automate this task using the following script:
for i in /apps/data/FILE*
do
echo "nice weather 20190830 friday" >> $i
done
It does the job yet I wish I can automate it more and let the script ask me for to provide the file name and the line I want to add.
I expect the output to be like
enter file name : file01
enter line to add : IWISHIKNOW HOWTODOTHAT
Thank you everyone.
In order to read user input you can use
read user_input_file
read user_input_text
read user_input_line
You can print before the question as you like with echo -n:
echo -n "enter file name : "
read user_input_file
echo -n "enter line to add : "
read user_input_text
echo -n "enter line position : "
read user_input_line
In order to add line at the desired position you can "play" with head and tail
head -n $[$user_input_line - 1] $user_input_file > $new_file
echo $user_input_text >> $new_file
tail -n +$user_input_line $user_input_file >> $new_file
Requiring interactive input is horrible for automation. Make a command which accepts a message and a list of files to append to as command-line arguments instead.
#!/bin/sh
msg="$1"
shift
echo "$msg" | tee -a "$#"
Usage:
scriptname "today is a nice day" file1 file2 file3
The benefits for interactive use are obvious -- you get to use your shell's history mechanism and filename completion (usually bound to tab) but also it's much easier to build more complicated scripts on top of this one further on.
The design to put the message in the first command-line argument is baffling to newcomers, but allows for a very simple overall design where "the other arguments" (zero or more) are the files you want to manipulate. See how grep has this design, and sed, and many many other standard Unix commands.
You can use read statement to prompt for input,
read does make your script generic, but if you wish to automate it then you have to have an accompanying expect script to provide inputs to the read statement.
Instead you can take in arguments to the script which helps you in automation.. No prompting...
#!/usr/bin/env bash
[[ $# -ne 2 ]] && echo "print usage here" && exit 1
file=$1 && shift
con=$1
for i in `ls $file`
do
echo $con >> $i
done
To use:
./script.sh "<filename>" "<content>"
The quotes are important for the content so that the spaces in the content are considered to be part of it. For filenames use quotes so that the shell does not expand them before calling the script.
Example: ./script.sh "file*" "samdhaskdnf asdfjhasdf"
for i in `cat ${DIR}/${INDICATOR_FLIST}`
do
X=`ls $i|wc -l`
echo $X
echo $X>>txt.txt
done
I have a code like this to check if file is present in a directory or not
but this is not working and gives error like this:
not foundtage001/dev/BadFiles/RFM_DW/test_dir/sales_crdt/XYZ.txt
You can see there is no space between not found and file path.
I have a code like this to check if file is present in a directory or not ...
It seems that you're trying to read a list of files from ${DIR}/${INDICATOR_FLIST} and then trying to determine if those actually exist. The main problem is:
You're trying to parse ls in order to figure whether the file exists.
This is what results in the sort of output that you see; mix of stderr and stdout. Use the test operator instead as given below.
The following would give tell you whether the file exists or not:
while read line; do
[ -e "${line}" ] && echo "${line} exists" || echo "${line} does not exist";
done < ${DIR}/${INDICATOR_FLIST}
Your file ${INDICATOR_FLIST} has CRLF line terminators (DOS-style). You need to strip out the CR characters, as Unix convention is for LF-only line terminators.
You can tell this by the way "not found" is printed at the start of the line. The immediately preceding character (the last char of the filename) is a CR, which sends the cursor back to the start of the line.
Find a dos2unix utility, or run tr -d \\015 over it (this deletes all CR's indiscriminately).
maybe the location of your file isn't ok.
take this example
m:~ tr$ echo "1 2 3 4 5" > file.txt
m:~ tr$ cat file.txt
1 2 3 4 5
m:~ tr$ for i in `cat file.txt`;do echo $i ;done
1
2
3
4
5
m:~ tr$
you could write the file before "for" and maybe check if the file exists:
echo "location : ${DIR}/${INDICATOR_FLIST}"
if [ -e ${DIR}/${INDICATOR_FLIST} ];then echo "file exists ";else echo "file was not found";fi
for i in `cat ${DIR}/${INDICATOR_FLIST}`;
do
let "X=`ls $i|wc -l`";
echo $X;
echo $X>>txt.txt;
done
The proper syntax is:
for i in `cat data-file`
do
echo $I
done
which you are following, therefore the problem must be in the specification of $DIR and $INDICATOR_LIST so therefore double check the location of your file.