cat using relative paths on mac - linux

I am trying to cat 4 files one directory down to a new file, also one directory down:
cat ./dira/file.txt ./dirb/file.txt ./dirc/file.txt ./dird/file.txt > ./dire/file.txt
I can get this to work from the Terminal, but not in the following:
for i in `ls -d prefix*`
do
cd $i
pwd
  cat ./dira/file.txt ./dirb/file.txt ./dirc/file.txt ./dird/file.txt > ./dire/file.txt
done
where pwd prints the correct directory. I get the error: -bash:  : command not found.

There must be a non-breaking space at the start of one of the lines in your file (easily done by typing option-space by accident during editing). The shell would consider that to be a word and try to run the non-breaking space as a command; this produces the "bash: : command not found" error that you see.

Related

How do you append a string built with interpolation of vars and STDIN to a file?

Can someone fix this for me.
It should copy a version log file to backup after moving to a repo directory
Then it automatically appends line given as input to the log file with some formatting.
That's it.
Assume existence of log file and test directory.
#!/bin/bash
cd ~/Git/test
cp versionlog.MD .versionlog.MD.old
LOGDATE="$(date --utc +%m-%d-%Y)"
read -p "MSG > " VHMSG |
VHENTRY="- **${LOGDATE}** | ${VHMSG}"
cat ${VHENTRY} >> versionlog.MD
shell output
virufac#box:~/Git/test$ ~/.logvh.sh
MSG > testing script
EOF
EOL]
EOL
e
E
CTRL + C to get out of stuck in reading lines of input
virufac#box:~/Git/test$ cat versionlog.MD
directly outputs the markdown
# Version Log
## version 0.0.1 established 01-22-2020
*Working Towards Working Mission 1 Demo in 0.1 *
- **01-22-2020** | discovered faker.Faker and deprecated old namelessgen
EOF
EOL]
EOL
e
E
I finally got it to save the damned input lines to the file instead of just echoing the command I wanted to enter on the screen and not executing it. But... why isn't it adding the lines built from the VHENTRY variable... and why doesn't it stop reading after one line sometimes and this time not. You could see I was trying to do something to tell it to stop reading the input.
After some realizing a thing I had done in the script was by accident... I tried to fix it and saw that the | at the end of the read command was seemingly the only reason the script did any of what it did save to the file in the first place.
I would have done this in python3 if I had know this script wouldn't be the simplest thing I had ever done. Now I just have to know how you do it after all the time spent on it so that I can remember never to think a shell script will save time again.
Use printf to write a string to a file. cat tries to read from a file named in the argument list. And when the argument is - it means to read from standard input until EOF. So your script is hanging because it's waiting for you to type all the input.
Don't put quotes around the path when it starts with ~, as the quotes make it a literal instead of expanding to the home directory.
Get rid of | at the end of the read line. read doesn't write anything to stdout, so there's nothing to pipe to the following command.
There isn't really any need for the VHENTRY variable, you can do that formatting in the printf argument.
#!/bin/bash
cd ~/Git/test
cp versionlog.MD .versionlog.MD.old
LOGDATE="$(date --utc +%m-%d-%Y)"
read -p "MSG > " VHMSG
printf -- '- **%s** | %s\n' "${LOGDATE}" "$VHMSG" >> versionlog.MD

I can't get my bash script to run

This is the script that I used to that will not run, but I am hoping someone can help me figure out what the issue is. I am new to unix
#!/bin/bash
# cat copyit
# copies files
numofargs=$#
listoffiles=
listofcopy=
# Capture all of the arguments passed to the command, store all of the arguments, except
# for the last (the destination)
while [ "$#" -gt 1 ]
do
listoffiles="$listoffiles $1"
shift
done
destination="$1"
# If there are less than two arguments that are entered, or if there are more than two
# arguments, and the last argument is not a valid directory, then display an
# error message
if [ "$numofargs" -lt 2 -o "$numofargs" -gt 2 -a ! -d "$destination" ]
then
echo "Usage: copyit sourcefile destinationfile"
echo" copyit sourcefile(s) directory"
exit 1
fi
# look at each sourcefile
for fromfile in $listoffiles
do
# see if destination file is a directory
if [ -d "$destination" ]
then
destfile="$destination/`basename $fromfile`"
else
destfile="$destination"
fi
# Add the file to the copy list if the file does not already exist, or it
# the user
# says that the file can be overwritten
if [ -f "$destfile" ]
then
echo "$destfile already exist; overwrite it? (yes/no)? \c"
read ans
if [ "$ans" = yes ]
then
listofcopy="$listofcopy $fromfile"
fi
else
listofcopy="$listofcopy $fromfile"
fi
done
# If there is something to copy - copy it
if [ -n "$listofcopy" ]
then
mv $listofcopy $destination
fi
This is what I got and it seems that the script didn't execute all though I did invoke it. I am hoping that someone can help me
[taniamack#localhost ~]$ chmod 555 tryto.txt
[taniamack#localhost ~]$ tryto.txt
bash: tryto.txt: command not found...
[taniamack#localhost ~]$ ./tryto.txt
./tryto.txt: line 7: $'\r': command not found
./tryto.txt: line 11: $'\r': command not found
./tryto.txt: line 16: $'\r': command not found
./tryto.txt: line 43: syntax error near unexpected token `$'do\r''
'/tryto.txt: line 43: `do
Looks like your file contains Windows new line formatting: "\r\n". On Unix, a new line is just "\n". You can use dos2unix (apt-get install dos2unix), to convert your files.
Also have a look at the chmod manual (man chmod).
Most of the time i just use chmod +x ./my_file to give execution rights
I see a few issues. First of all, a mode of 555 means that no one can write to the file. You probably want chmod 755. Second of all, you need to add the current directory to your $PATH variable. In Windows, you also have a %PATH%, but by default the current directory . is always in %PATH%, but in Unix, adding the current directory is highly discouraged because of security concerns. The standard is to put your scripts under the $HOME/bin directory and make that directory the last entry in your $PATH.
First of all: Indent correctly. When you enter a loop or an if statement, indent the lines by four characters (that's the standard). It makes it much easier to read your program.
Another issue is your line endings. It looks like some of the lines have a Windows line ending on them while most others have a Unix/Linux/Mac line ending. Windows ends each line with two characters - Carriage Return and Linefeed while Unix/Linux/Mac end each line with just a Linefeed. The \r is used to represent the Carriage Return character. Use a program editor like vim or gedit. A good program editor will make sure that your line endings are consistent and correct.

Recursive grep with include giving incorrect results for current folder

I have created a test directory structure:
t1.html
t2.php
a/t1.html
a/t2.php
b/t1.html
b/t2.php
All files contain the string "HELLO".
The following commands are run from the root folder above:
> grep -r "HELLO" *
b/t1.html:HELLO
b/t2.php:HELLO
c/t1.html:HELLO
c/t2.php:HELLO
t1.html:HELLO
t2.php:HELLO
> grep -r --include=*.html "HELLO" *
b/t1.html:HELLO
c/t1.html:HELLO
t2.php:HELLO
Why is it including the correct .html files from the sub-directories, but the .php file from the current directory?
If I pop up a level to the directory above my whole structure, then it gives following result:
grep -r --include=*.html "HELLO" *
a/t1.html:HELLO
a/c/t1.html:HELLO
a/b/t1.html:HELLO
This is what I expected when ran from within my structure.
I assume I can achieve the goal using find+grep together, but I thought this was valid usage of grep.
Thanks for any help.
Andy
Use a dot instead of the asterisk:
grep -r HELLO .
Asterisk gets evaluated by the shell and replaced with the list of all the files in the current directory (whose names don't start with a dot). All of them are then grepped recursively.

how to avoid non printable characters in for each loops (shell scripting)

I wrote a shell script as follows
for i in `readlink -f rec*`:
do
cd $i
pwd
cd ..
pwd
done
The following are the details of corresponding directories:
readlink -f rec*
/home/sandilya/part655gib/recup_dir.1
/home/sandilya/part655gib/recup_dir.2
/home/sandilya/part655gib/recup_dir.3
/home/sandilya/part655gib/recup_dir.4
/home/sandilya/part655gib/recup_dir.5
the script output:
/home/sandilya/part655gib/recup_dir.1
/home/sandilya/part655gib
/home/sandilya/part655gib/recup_dir.2
/home/sandilya/part655gib
/home/sandilya/part655gib/recup_dir.3
/home/sandilya/part655gib
/home/sandilya/part655gib/recup_dir.4
/home/sandilya/part655gib
mvrec.sh: 5: cd: can't cd to /home/sandilya/part655gib/recup_dir.5:
/home/sandilya/part655gib
/home/sandilya
The problem is that last directory is left out.. I was expecting that the last entry is combined with a non printable character. Permissions are all okay with the directories.
Please help me out of this mess. Thanks in advance
The problem is more apparent than it looks. There is no non-printable character.
Let's take a look a cd error message from dash, the shell you're using instead of bash:
$ cd somewhere
dash: 5: cd: can't cd to somewhere
^-- Nothing follows the path
Now look at your error message:
mvrec.sh: 5: cd: can't cd to /home/sandilya/part655gib/recup_dir.5:
Spurious colon ---^
And where does this colon come from?
for i in `readlink -f rec*`:
^--- Right here
Delete it, and it'll work.
(Note that this is not canonical or entirely correct code, and people's suggestions about for f in rec* loops and subshells still apply.)

Check if directory exists not working

I have a textfile (qrs.txt) which contains dir names (one per line) and on my server in the same directory as the script I have those folders with corresponding names from the text file.
This is my script:
#!/bin/bash
while read p; do
if [ ! -d "$p" ];
then
echo "ERROR $p" >> log.txt
else
echo "GOOD" >> log.txt
fi
done < qrs.txt
qrs.txt:
1992300000183805
1992300001176204
1992300002145500
1992300003104507
1992300004104902
1992300005133703
1992300006117802
1992300007144501
1992300008172803
1992300009189005
1992300010146307
1992300011151700
1992300012190007
1992300013126802
1992300014111508
1992300015193908
When that if statement is inside the loop it always returns error which is incorrect because I can see the folders exist. When I take it out of the loop and check for just 1, it works fine... When I echo $p on the same line as error, I can see the file name its checking is indeed correct.
What am I missing here..?
EDIT:
Screenshot of qrs.txt in hex mode:
http://i.snag.gy/25mqJ.jpg
RESOLVED!
My qrs.txt was in [dos] format originally but once converted to unix format using ":set ff=unix" the script worked like a charm!
Your script works fine.
I copied your script to my local machine. When I put blh blah in the qrs.txt file, I got ERROR for each time I ran your script. I ran it four times. I changed the blh blah to a valid path and I received GOOD.
The directory 1992300000183805 for instance, may be not be a valid path. You need the fully qualified path name! For example, /home/user/1992300000183805.
ERROR blh blah
ERROR blh blah
GOOD
GOOD
EDIT
Looking at #chepner comments, I recreated your problem:
Open your qrs.txt file in vi or vim. You should see ^M at the end of your lines. To remove the ^M characters at the end of all lines in vi, use:
:%s/^M//g
This should fix your problem. If not, in vim type this:
:set ff=unix
save the file.
Re-open qrs.txt in vim, then run the regex above again, or manually delete the ^M.
Or you can use perl:
perl -pi -e "s/\r/\n/g;" <file>
OK so looking at your provided file it seems those are relative directory names -- as such current directory is very important when you execute the script. Do you execute the script from its own directory or from the parent directory to all the (sub)directories shown in your example?
In other words have you tried:
cd <parent directory>
/path/to/yourscript.sh
?
Not to mention the location of qrs.txt seems to be specified relative rather than absolute path. So if there's no qrs.txt in the current directory I don't think your script would work.

Resources