Bash - cat in a hidden . file or write to it - linux

Let's say I make a file .history.txt:
touch .history.txt
and I try to write to it:
cat > .history.txt
after having done that all I get is:
bash: .history.txt: is a directory
What I need is to be able to write some text to it like I would be able to any normal file. Any ideas what am I doing wrong?

A file doesn't need to already exist in order to redirect output to it (the shell will create the file if necessary). But Bash is telling you that .history.txt already exists and is a directory, so you can't write to it.
You either need to remove the existing directory rm -rf .history.txt or use a different file name. Then cat > .whatever.txt should work on its own.

Related

Move files between directories using shell script

I'm new to linux and shell script in general. I'm using a distribution of Debian on the WSL (Windows Subsystem for Linux). I'm trying to write a very simple bash script that will do the following:
create a file in a directory (child-directory-a)
move to the directory it is in
move the file to another directory (child-directory-b)
move to that directory
move the file to the parent directory
This is what I have so far (trying to keep things extremely simple for now)
touch child-directory-a/test.txt
cd child-directory-a
mv child-directory-a/test.txt home/username/child-directory-b
The first two lines work, but I keep getting a 'no such directory exists' error with the last one. The directory exists and that is the correct path (checked with pwd). I have also tried using different paths (i.e. child-directory-b, username/child-directory-b etc.) but to no avail. I can't understand why it's not working.
I've looked around forums/documentation and it seems that these commands should work as they do in the command line, but I can't seem to do the same in the script.
If anyone could explain what I'm missing/not understanding that would be brilliant.
Thank you.
You could create the script like this:
#!/bin/bash
# Store both child directories on variables that can be loaded
# as environment variables.
CHILD_A=${CHILD_A:=/home/username/child-directory-a}
CHILD_B=${CHILD_B:=/home/username/child-directory-b}
# Create both child folders. If they already exist nothing will
# be done, and no error will be emitted.
mkdir -p $CHILD_A
mkdir -p $CHILD_B
# Create a file inside CHILD_A
touch $CHILD_A/test.txt
# Change directory into CHILD_A
cd $CHILD_A
# Move the file to CHILD_B
mv $CHILD_A/test.txt $CHILD_B/test.txt
# Move to CHILD_B
cd $CHILD_B
# Move the file to the parent folder
mv $CHILD_B/test.txt ../test.txt
Take into account the following:
We make sure that all the folders exists and are created.
Use variables to avoid typos, with the ability to load dynamic values from environment variables.
Use absolute paths to simplify the movement between folders.
Use relative paths to move files relatives to where we are.
Another command that might be of use is pwd. It will tell you the directory you are on.
with your second line, you change the current directory to child-directory-a
so, in your third line there is an error because there is no subdirectory child-directory-a into subdirectory child-directory-a
Your third line should be instead :
mv test.txt ../child-directory-b
The point #4 of your script should be:
cd ../child-directory-b
(before that command the current directory is home/username/child-directory-a and after this command it becomes home/username/child-directory-b)
Then the point #5 and final point of your script should be:
mv test.txt ..
NB: you can display the current directory at any line of your script by using the command pwd (print working directory) in your script, it that helps
#!/bin/sh
# Variables
WORKING_DIR="/home/username/example scripts"
FILE_NAME="test file.txt"
DIR_A="${WORKING_DIR}/child-directory-a"
DIR_B="${WORKING_DIR}/child-directory-b"
# create a file in a directory (child-directory-a)
touch "${DIR_A}/${FILE_NAME}"
# move to the directory it is in
cd "${DIR_A}"
# move the file to another directory (child-directory-b)
mv "${FILE_NAME}" "${DIR_B}/"
# move to that directory
cd "${DIR_B}"
# move the file to the parent directory
mv "${FILE_NAME}" ../

How to delete .jpg file in linux console

By accident I named my image file wrong so I wanted to delete it. So I typed the following in my linux console:
rm localapps\logo.jpg
But it didn't work.
Then I wrote
rm *.jpg
then it worked. Simple question. Why did the first not work , even I know that is the way to delete files in linux?
We would need the output of the commands you are running. You typically have no output when the command succeeds.
It is also important for you to notice that in linux, the / character is used to denote directories, and not \, which is actually typically the escape character.
In a terminal is also very important for you to notice in which directory are you working and what is the relative path to the file you want to refer to. You can find this out with the command pwd that stands for print working directory.
You would see something like
your-box:~ blurry$ pwd
/home/blurry
your-box:~ blurry$
This said, when you type
rm localapps\logo.jpg
since \ is a escape character, this is interpreted as
rm localappslogo.jpg
this means, it is looking for the file named localappslogo.jpg in the current directory (/home/blurry/localappslogo.jpg).
I assume that file does not exist, then, it will output something like:
rm: localappslogo.jpg: No such file or directory
when you type
rm *.jpg
this code removes any file ending in .jpg in the current directory. So notice that if you were trying to delete a file that was in the localapps folder, you should use instead
rm localapps/logo.jpg
But this is always assuming that the relative path to your image is localapps/logo.jpg.
You can also change directory then delete the file like this,
cd localapps
rm logo.jpg

shell script : appending directory path and filename

I want to copy a file from a directory using shell script
Suppose I save the directory and file name seperately as
dir=/home/user/directory/
file=file_1
to copy the file Im using this command in my script
cp $dir$file .
But I get this error
/bin/cp omitting directory '/home/user/directory'
I have tried all combination eg. omitted the trail backslah from variable dir, etc but nothings working. I cant understand what is wrong with this code. Pleas help
Maybe the command $dir$file is not getting unpacked in the shell (ie only the directory variable is getting unpacked, not the file variable)!!!!!
It looks like you are having problem with expansion in cp $dir$file . In order to prevent possible problems, it is better to protect your variable with braces and double quote the full path/file to make sure you don't get caught by spaces in either the filename or heaven forbid the user's dirname:
cp "${dir}${file}" .
This will prevent the possibility the second $ is missed. Also make sure you have read access to other users /home (if you are root or using sudo you should be fine)
If you see this, when you somehow assign an empty string to file somewhere. Search your script for file= and unset file.
You can also debug this by adding
echo ".${file}."
in the line before the cp command. I'm pretty sure it prints .., i.e. the variable is empty or doesn't exist.

"Spoof" File Extension In Bash

Is there a way to "spoof" the file extension of a file in bash for consumption by another program? I can think of doing some shell scripting and making lots of soft-links, but that isn't very scalable.
Let's imagine I have a program I'm trying to use that requires input files to be of a specific file extension, and it has no method of turning off this check.
You could make a fifo with the requisite extension and cat any other file type into it. So, if your crazy program needs to see files that end in .funky, you can do this:
mkfifo file.funky
cat someotherfile > file.funky &
someprogram file.funky
Create a symbolic link for each file you want to have a particular extension, then pass the name of the symlink to the command.
For example suppose you have files with names of the form *.foo and you need to refer to them with extensions of .bar:
for file in *.foo ; do
ln -s $file _$$_$file.bar
done
I precede each symlink name with _$$_ to avoid the possibility of colliding with an existing file name (you don't want to do ln -s file.foo file.bar if file.bar already exists).
With a little more programming, your script can keep track of which symlinks it created and, if you like, clean them up after executing the command.
This assumes, as you stated in the question, that the command can't be forced to accept a different extension.
You could, without too much difficulty, create a wrapper script that replaces the command in question, creating the symlinks, invoking the command, and cleaning up after itself automatically.

Pass input and output files desired PATH to a binary in bash

In a bash script called through shell in some directory ($PWD), there is a line where I need to call an executable located at $PWD/bin so that it reads a input file located at $PWD/inputfiles and the resulting output files are stored in $PWD/output.
Can this be achieved?
PS: Now if I am at
cd /home/user
I do
./run config.inp output.dat
with config.inp being at /home/user
config.inp reads files data.txt and lines.txt which are in the same directory.
Now I want to read from /home/user/input and write the output files to /home/user/output
and I try
./run input/config.inp
it says
error, data.txt not found
As the problem is described, this will do it:
bin/executable < inputfiles/input > output/output
If the problem is really that bin/executable creates files in the current directory without allowing the user to specify the input and output files, then it will be a little more complicated. What you would probably want to do instead is:
cd output
ln -s ../inputfiles/input
../bin/executable
rm input
This will create a symbolic link to inputfiles/input from within the output directory, and then delete it later. If you want to eliminate the chance of collisions with files in the output directory, then you need to create a temporary directory with something like TMPDIR = $(mktemp -d), do everything there, and then copy it back to $OLDPWD/output.

Resources