tail -f did not continue output the new lines added using vi - unix

When I invoked "tail -f myfile.txt", the new line added using the following command output the new line, but not the line added/saved using vi. Does anyone know why ?
$echo "this is new line" >> myfile.txt
Thanks.

It has something to do w/the fact that while you are editing the file, vi keeps your changes in a second file (.myfile.txt.swp in this case).
When you save the changes, it's likely that vi is replacing the original file w/the second file. This means the file that tail was watching is no longer valid.
To prove this, try your echo command after saving the file with vi. When you do that, the output won't be displayed by tail.

The tail program opens a file, seeks to the end, and (with "-f") waits, then checks again if that open file has anything new to read.
vi does not append to a file. It makes a copy, (not a "swap", which is something else altogether) writes it out, and then moves the new file to have the same name as the old file.
tail is still watching the old file, not looking up a file by that file name every time.
In addition, tail uses the location in the file, so if you delete 10 characters and add 15, the next loop of 'tail' will emit the next 5 it thinks are new because they are after its placeholder.
Run 'tail --follow=name ...' to get tail to look up the file every loop by name, instead of watching the location on disk of a file it opens at start.

Related

How can I change PATH variable in zsh?

I want to change my PATH variable in zsh.
Problem: I don't understand where in the .zshrc file I have to make modifications.
Normally, I would look for the assignment to the PATH variable and set the values from scratch how I would like them to be (leaving all the systems binaries directories untouched).
The first lines in my .zshrc file are as follows:
# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:/usr/local/bin:$PATH
# Path to your oh-my-zsh installation.
export ZSH="/Users/Sam/oh-my-zsh"
export PATH=$PATH:/Applications/Postgres.app/Contents/Versions/13/bin
etc.
My actual PATH variable is:
/Library/Frameworks/Python.framework/Versions/3.9/bin:/Library/Frameworks/Python.framework/Versions/3.8/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Postgres.app/Contents/Versions/13/bin
I want to delete the directory where python3.8 is in, it's redundant.
My questions:
Do I have to change line 2 or line 7 in my .zshrc file?
Line 2 is commented out...is it executed anyway at the start of the terminal?
I have tried to comment out line 7. But the postgres directory still remained in my PATH variable which I don't understand.
The .zshrc is located in the home dir. The dot at the beginning keeps it hidden. Type ls -a from ~ directory to see it. To edit just run vim, nvim, etc as usual.
nvim ~/.zshrc
This is the command for Neovim. For your editor, sub nvim for the proper command.
Once you get in, you need only add the same export command that you would add from the command line.
export PATH=$PATH:/whatever/you/are/adding
EDIT
To remove a path variable:
First, run the command:
echo $PATH
from the command line.
Next, Copy the output to clipboard.
Finally, at the very end of the .zshrc file, add the following:
export PATH=<paste-what-you-copied-here>
Because you didn't reference $PATH after the =, this will set the path to EXACTLY what you pasted, no more, no less. Adding $PATH: as in the first example will just add whatever to the end of what is already there.
Since this gives you access to every item in the path array, deleting is just a matter of a literal highlight/select and of whatever you want deleted.
Finally, be sure that there is only one place in the file where you are editing PATH. If there are more than one, the result can be confusing to say the least.
That said, I believe the script runs top-to-bottom, so only the last mention should persist. You can take advantage of this in some situations, but for this purpose, one will suffice. XD
Be careful when you decide to fiddle with the PATH in .zshrc: Since the file is processed by every interactive subshell, the PATH would get longer and longer for each subshell, with the same directory occuring in it several times. This can become a nightmare if you later try to hunt down PATH-related errors.
Since you are using zsh, you can take advantage that the scalar variable PATH is mirrored in the array variable path, and that you can ask zsh to keep entries in arrays unique.
Hence, the first thing I would do is put a
typeset -aU path
in your .zshrc; this (due to mirroring) also keeps the entries in PATH unique. You can put this statement anywhere, but I have it for easier maintenance before my first assignment to PATH or path.
It is up to you to decide where exactly you add a new entry to PATH or path. The entries are searched in that order which is listed in the variable. You have to ask yourself two questions:
Are some directories located on a network share, where you can sometimes expect access delays (due to bad network conditions)? Those directories should better show up near the end of the path.
Do you have commands which occur in more than one directoryin your path? In this case, a path search will always find the first occurance only.
Finally, don't forget that your changes will be seen after zsh processes the file. Therefore, you could create a new subshell after having edited the file, or source .zshrc manually.

Check if a file is open using Windows command line within R

I am using the shell() command to generate pdf documents from .tex files within a function. This function sometimes gets ran multiple times with adjusted data and so will overwrite the documents. Of course, if the pdf file is open when the .tex file is ran, it generates an error saying it can't run the .tex file. So I want to know whether there are any R or Windows cmd commands which will check whether a file is open or not?
I'm not claiming this as a great solution: it is hacky but maybe it will do. You can make a copy of the file and try to overwrite your original file with it. If it fails, no harm is made. If it succeeds, you'll have modified the file's info (not the contents) but since your end goal is to overwrite it anyway I doubt it will be a huge problem. In either case, you'll be fixed about whether or not the file can be rewritten.
is.writeable <- function(f) {
tmp <- tempfile()
file.copy(f, tmp)
success <- file.copy(tmp, f)
return(success)
}
openfiles /query /v|(findstr /i /c:"C:\Users\David Candy\Documents\Super.xls"&&echo File is open||echo File isn't opened)
Output
592 David Candy 1756 EXCEL.EXE C:\Users\David Candy\Documents\Super.xls
File is open
Findstr returns 0 if found and 1+ if not found or error.
& seperates commands on a line.
&& executes this command only if previous command's errorlevel is 0.
|| (not used above) executes this command only if previous command's errorlevel is NOT 0
> output to a file
>> append output to a file
< input from a file
| output of one command into the input of another command
^ escapes any of the above, including itself, if needed to be passed to a program
" parameters with spaces must be enclosed in quotes
+ used with copy to concatinate files. E.G. copy file1+file2 newfile
, used with copy to indicate missing parameters. This updates the files modified date. E.G. copy /b file1,,
%variablename% a inbuilt or user set environmental variable
!variablename! a user set environmental variable expanded at execution time, turned with SelLocal EnableDelayedExpansion command
%<number> (%1) the nth command line parameter passed to a batch file. %0 is the batchfile's name.
%* (%*) the entire command line.
%<a letter> or %%<a letter> (%A or %%A) the variable in a for loop. Single % sign at command prompt and double % sign in a batch file.
.
--

change file extension in unix

I am taking a intro to Unix class and am stuck on the final assignment. I need to write a script to change the file extension of a filename that is input when the script is run. The new file extension is also input when the script is run. The script is call chExt1.sh . Our first trial of the script is run as follows
./chExt1.sh cpp aardvark.CPP
The script is suppose to change the second input file extension to the file extension given in the first input. It is not suppose to matter what file extension is given with the file name or what file extension is given as the new extension, nor is it only for changing uppercase to lowercase. In hope to make this very clear if given the following:
./chExt1.sh istink helpme.plEaSe
The script would change helpme.plEaSe to helpme.istink . I have searched on this forum and in google and have had no look with trying the different examples I found. Below is some of the examples I have tried and what I currently have.
Current
#!/bin/sh
fileExtension="$1"
shift
oldName="$2"
shift
newName=${oldName%%.*}${fileExtension}
echo $newName
The echo is just to see if it works, and if I get it working I'm going to add an mv to save it.
Others that I have tried:
newName=`${oldName%.*}`
newName=`${oldName#.*}`
sed 's/\.*//' $oldName > $newName
I can't seem to find some of the other sed I have used but they involved alot of backslashes and () with .* in there. I did not try the basename command cause I don't know the file extension to be entered and all I the examples I saw required that you specify what you wanted removed and I can't. I did not list all the different quote variations that I used but I have tried alot. My instructions say to use the sed command since we should know how to use that from class but when I try to do it I don't isolate just the ending of the file and I believe (cause it takes so long to finish) that it is going through the whole file and looking for .'s and anything after cause I kept doing .* as the pattern. Thanks for anyhelp you can give.
shift shifts the positional parameters, so after calling shift the second parameter ($2) is now the first ($1). The second shift is not necessary, because you are done accessing the parameters. You need to either remove the shift
#!/bin/sh
fileExtension="$1"
oldName="$2"
newName=${oldName%%.*}${fileExtension}
echo $newName
or change $2 to $1.
#!/bin/sh
fileExtension="$1"
shift
oldName="$1"
newName=${oldName%%.*}${fileExtension}
echo $newName
However, you are still missing a dot from your new file name. That is left as an exercise for the reader.

How do i read, modify and write to the same file without involving a temporary file in zsh?

I like keeping my history files uncluttered. Since zsh has excellent history searching features, there is no need to save all the commands that I repeatedly use (e.g., finger, pwd, ls, etc) multiple times. To strip the history file of all duplicate lines, I did sort .zhistory|uniq -du. Now, I'd like to write this back to the same file, so that if I simply put this in my .zshrc, everytime I login, my history is trimmed and clean. If I try sort .zhistory|uniq -du>.zhistory, the resulting file is empty! On the other hand, if I do sort .zhistory|uniq -du>tempfile, it writes to tempfile correctly. Any idea how I can write to the same file?
You might be able to use a variable:
file='.zhistory' && var=$(sort -u "$file") && echo "$var" > "$file"
The reason you can't write to the same file is that the redirection occurs first and truncates the file before the utility ever sees it.
You can prevent duplicate lines in the first place. Use setopt with one or more of the following settings (from man zshoptions):
HIST_EXPIRE_DUPS_FIRST
If the internal history needs to be trimmed to add the current
command line, setting this option will cause the oldest history
event that has a duplicate to be lost before losing a unique
event from the list. You should be sure to set the value of
HISTSIZE to a larger number than SAVEHIST in order to give you
some room for the duplicated events, otherwise this option will
behave just like HIST_IGNORE_ALL_DUPS once the history fills up
with unique events.
HIST_FIND_NO_DUPS
When searching for history entries in the line editor, do not
display duplicates of a line previously found, even if the
duplicates are not contiguous.
HIST_IGNORE_ALL_DUPS
If a new command line being added to the history list duplicates
an older one, the older command is removed from the list (even
if it is not the previous event).
HIST_IGNORE_DUPS (-h)
Do not enter command lines into the history list if they are
duplicates of the previous event.
HIST_SAVE_NO_DUPS
When writing out the history file, older commands that duplicate
newer ones are omitted.
The program sponge can be useful to write back in the same file you read.
(For the example's sake, you don't know about sed -i)
echo "say what again" > file
sed s/what/woot/ file > file
So bad, file is now empty, you lost your file.
echo "say what again" > file
sed s/what/woot/ file | sponge file
does what you want
(Be careful not to write sponge > file or the file will be empty again.)
The fact that i didn't have an answer to this question annoyed me sufficiently that i wrote one - call this inplace and put it executably on your path:
#! /bin/bash
BACKUP_EXT=
while getopts "b:" flag
do
case "$flag" in
b) BACKUP_EXT="$OPTARG" ;;
esac
done
shift $((OPTIND - 1))
CMD="$1"
shift
for filename in "$#"
do
TMP_FILE="$(mktemp -t)"
bash -c "$CMD" <"$filename" >"$TMP_FILE"
if [[ -n "$BACKUP_EXT" ]]
then
mv "$filename" "$filename.$BACKUP_EXT"
fi
mv "$TMP_FILE" "$filename"
done
You may now say:
inplace 'sort | uniq -du' .zhistory
Incidentally, there's a way to do that uniqification without having to sort - but that's an answer for another question!

Unable to change a pipe to be a normal file

I have the following file (above) which seems to be an Unix pipe
alt text http://dl.getdropbox.com/u/175564/problemFile.png
How can you make the pipe a default text file?
Unless there is some other complication that hasn't been mentioned, the easiest is to use the big hammer:
$ rm outside
$ touch outside
If there is a process currently using the file, you will need to kill the process first, then restart it so it uses the new file. Otherwise, the pipe will stay open but invisible until the process finally dies.
How can you make the pipe a default
text file, such that the first letter
changes to d?
The first character of 'd' means that that entry is a directory - not a normal file.

Resources