How do you quit without saving when using vim -c flag - vim

I want to run something along the lines of
vim -r -c "w %.new | q!" ${filename}
However, the ! is parsed as the prefix for an external command. Similar issues happen when using single quotes.
I could work around this with the following code, but it feels much less clean or obvious than the previous code.
cp ${filename} ${filename}.new && mv .${filename}.swp .${filename}.new.swp;
vim -r -c "wq" ${filename}.new;

Use single quotes instead of double quotes. The ! is being interpreted in bash not vim.
vim -r -c 'w %.new | q!' ${filename}
! followed by test runs the last command that starts with that text. In this case bash looks for a command starting with " which isn't found. The single quotes stops bash from interpreting the !
Some examples of using ! in bash
It seems the actual problem was that %.new existed. To just force over write use w! instead of w
vim -r -c 'w! %.new | q!' ${filename}

Related

How can I give special command (insert) to vi?

I remember doing magic with vi by "programming" it with input commands but I don't remember exactly how.
My sepcial request are:
launch vi in a script with command to be executed.
do an insert in one file.
search for a string in the file.
use $VARIABLE in the vi command line to replace something in the command.
finish with :wq.
I my memory, I sent the command exactly like in vi and the ESC key was emulate by '[' or something near.
I used this command into script to edit and change files.
I'm going to see the -c option but for now I cannot use $VARIABLE and insert was impossible (with 'i' or 'o').
#!/bin/sh
#
cp ../data/* .
# Retrieve filename.
MODNAME=$(pwd | awk -F'-' '{ print $2 }')
mv minimod.c $MODNAME.c
# Edit and change filename into the file (from mimimod to the content of $VARIABLE).
vi $MODENAME.c -c ":1,$s/minimod/$MODNAME/" -c ':wq!'
This example is not functionning (it seems the $VARIABLE is not good in -c command).
Could you help me remember memory ;) ?
Thanks a lot.
Joe.
You should not use vi for non-interactive editing. There's already another tool for that, it's called sed or stream editor.
What you want to do is
sed -i 's/minimod/'$MODNAME'/g' $MODNAME.c
to replace your vi command.
Maybe you are looking for the ex command, that can be run non-interatively:
ex $MODENAME.c <<< "1,\$s/minimod/$MODNAME/
wq!
"
Or if you use an old shell that does not implement here strings:
ex $MODENAME.c << EOF
1,\$s/minimod/$MODNAME/
wq!
EOF
Or if you do not want to use here documents either:
echo "1,\$s/minimod/$MODNAME/" > cmds.txt
echo "wq!" >> cmds.txt
ex $MODENAME.c < cmds.txt
rm cmds.txt
One command per line in the standard input. Just remember not to write the leading :. Take a look at this page for a quick review of ex commands.
Granted, it would be better to use the proper tool for the job, that would be sed, as #IsaA answer suggests, or awk for more complex commands.

How to delete multiple history entries from ~/.bash_history using scripts?

I wanted to delete commands that are common (such as pwd, ls -l, cd, ) and keep the ones that I might forget how to use. To do this I ran the following commands
history | grep "cd$" | cut -c 1-5 > ~/sandboxArea/histDelTemp.txt
cntr=0; for i in $(cat ~/sandboxArea/histDelTemp.txt); do var=`expr $i - $cntr`; history -d $var; cntr=`expr $cntr + 1`; done; unset cntr
After running the above command if I again run to check if everything was deleted using the following command
history | grep "cd$"
then it seems that everything is in fact deleted and the above command produces no output.
However, if I close the terminal and again run the above command then everything seems to re-appear. Why is it so? Does bash has functionality to backup_restore commands?
Thanks in advance

How can I delete the oldest n group of files with the same prefix?

In Linux I use InfluxDB which can make a backup of the database for archival purposes. Each backup comprises a series of files with the same prefix "/tank/Backups/var/Influxdb/20191225T235655Z." and different extensions.
I wanted to write a bash script which first deletes the oldest existing backups, then creates a new one (here I paste only the removal):
ls -tp /tank/Backups/var/Influxdb/* | grep -v '/$' | sed -E 's/\..+//' | \
sort -ru | sed 's/$/.*/' | tail -n +4 | xargs -d '\n' -r rm --
However, when I run the script as "sudo", I get
rm: cannot remove '/tank/Backups/var/Influxdb/20191225T235655Z.*': No such file or directory
When I run the quoted script, except the latest part, I get:
/tank/Backups/var/Influxdb/20190930T215357Z.*
/tank/Backups/var/Influxdb/20190930T215352Z.*
which is correct. Also, if I manually write
sudo /tank/Backups/var/Influxdb/20190930T215357Z.*
the command succeeds.
Why is the script reporting an error?
I'm using Ubuntu 18.04 and the folder "/tank" is a ZFS volume.
Better do :
find /tank/Backups/var/Influxdb/* -mtime +5 -delete
to remove files older than 5 days.
Then, you can run the next command
Explaining the Error
This answer is only here to explain the error and give a deeper understanding of what is happening. If you are simply looking for an elegant solution search for other answers.
When I run the quoted script, except the latest part, I get:
/tank/Backups/var/Influxdb/20190930T215357Z.*
/tank/Backups/var/Influxdb/20190930T215352Z.*
which is correct
The listed strings are not what you want. When you pass these paths to rm it sees them just as literal strings, that is, two files whose names end with a literal *. Since you don't have such files you get an error.
When you type rm * manually into your console bash (not rm!) does globbing. bash searches files and replaces the * with the list of found files. Only after that bash executes rm foundFile1 foundFile2 .... rm never sees the *.
Strings inside a pipeline are not processed by bash, but by the commands in the pipeline, in your case rm. rm does not glob.
You could run bash inside your pipeline and let it expand the * you inserted earlier. To this end, replace the last command in your pipeline with xargs -r bash -c 'rm -- $*' --. However, note that your paths are not quoted here. If there are spaces or literal * in your filenames the command will break. This is necessary for globbing as quoted "*" are not expanded by bash.
To quote your files you have to insert the * glob inside the bash command:
ls -tp /tank/Backups/var/Influxdb/* | grep -v '/$' | sed -E 's/\..+//' |
sort -ru | tail -n +4 | xargs -d\\n -L1 -r bash -c 'rm -- "$0."*'
Above command is only a simple fix for your command. It is neither elegant nor very robust. Using tools like find is strongly recommended.

Curl/sed command not processing inputs correctly

I'm having some trouble with getting this to do what I want it to do.
read -p "URL to read: " U
read -p "Word to fin: " O
read -p "Filename: " F
curl -O $U | sed "s/\<$O\>/\*$O\*/g" > $F.txt
So basically what I want is to use curl to get a .txt file from a url, then sort through it to find the word specified by the user input. Then mark all those words with a * and put them in a file specified by the user.
Almost the exact same code works in Linux, but this doesn't work on my Mac. Anyone got an idea?
Two issues:
-O makes curl store the downloaded file, not output it on stdout.
word boundary metacharacters \< and \> are a GNU extension. On BSD sed, you can use [[:<:]] and [[:>:]] instead.
This should work on OSX:
curl "$U" | sed "s/[[:<:]]$O[[:>:]]/\*$O\*/g" > $F.txt

Linux cat command output with new lines to be read using vim

I am trying to open all the files listed in file a.lst:
symptom1.log
symptom2.log
symptom3.log
symptom4.log
But trying the following command:
cat a.lst | tr "\n" " " | vim -
opens only the stdin output
symptom1.log symptom2.log symptom3.log symptom4.log
It doesn't open symptom1.log, symptom2.log, symptom3.log & symptom4.log in vim.
How to open all the files listed in a.lst using vim?
You could use xargs to line upp the arguments to vi:
vim $(cat 1.t | xargs)
or
cat a.lst | xargs vim
If you want them open in split view, use -o (horizontal) or -O (vertical):
cat a.lst | xargs vim -o
cat a.lst | xargs vim -O
while read f ; do cat $f ; done < a.lst | vim -
I like a variation on Qiau's xargs option:
xargs vim < a.lst
This works because the input redirection is applied to the xargs command rather than vim.
If your shell is bash, another option is this:
vim $(<a.lst)
This works because within the $(...), input redirection without a command simply prints the results of the input, hence expanding the file into a list of files for vim to open.
UPDATE:
You mentioned in comments that you are using csh as your shell. So another option for you might be:
vim `cat a.lst`
This should work in POSIX shells as well, but I should point out that backquotes are deprecated in some other shells (notably bash) in favour of the $(...) alternative.
Note that redirection can happen in multiple places on your command line. This should also work in both csh and bash:
< a.lst xargs vim
vim may complain that its input is not coming from a terminal, but it appears to work for me anyway.

Resources