Linux command and single quote - linux

I thought the single quotes simply reserve the literal value of each character within the quotes and do not interfere with the command result except for those character-escaping situations.
For example, the two commands below returned the same result.
$ ls /home/testuser/tmp1
$ ls '/home/testuser/tmp1'
This command below ran successfully.
$ cp /home/testuser/tmp1/* /home/testuser/tmp2
However, the command below ran into error.
$ cp '/home/testuser/tmp1/*' /home/testuser/tmp2
cp: cannot stat '/home/testuser/tmp1/*': No such file or directory
What did I do wrong here?

* is what you call a character escaping situation. Since you preserved the literal value of *, it lost its meaning of "all files", and cp instead tries to copy a file named literally *.
When you run:
cp /home/testuser/tmp1/* /home/testuser/tmp2
The shell will transparently rewrite it into:
cp /home/testuser/tmp1/bar /home/testuser/tmp1/foo /home/testuser/tmp2
This process is known as "pathname expansion" or "globbing". When you quote the *, this rewrite does not happen.

Related

how to specify path with space inside file in linux

cat ~/.last_dir
/mnt/c/Users/Administrator/OneDrive/Desktop/main project/backup/main project 2
cd cat ~/.last_dir
-bash: cd: too many arguments
I tried using backslash inside the file
/mnt/c/Users/Administrator/OneDrive/Desktop/main\ project/backup/main\ project\ 2
Still same error
You need to quote the results of expanding cat ...:
cd "$(cat ~/.last_dir)"
cd "$(<~/.last_dir)"
First, put quotes around the $(...) to make the space part of the filename.
Second, $(<...) is a bash construct that reads the file directly without executing cat, but is not entirely portable.
For a more generic, less bash-specific version, use Maxim's solution.
just put quotation marks around your path:
"/mnt/c/Users/Administrator/OneDrive/Desktop/main project/backup/main project 2"
this should work for most cases

string manipulation of Directory structure

Scenario: I have a script but no idea where I am in the directory tree, I need to resolve back to the nearest known location UPROC[something]
What I have so far:
I have a script running in a directory for example:
/home/jim/query/UPROCL/test/bob/dircut.sh
now the only constant in this is that the Directory I want will begin with UPROC... maybe not UPROCL but definitely UPROC
So I have written the following:
#!/bin/bash
#Absolute path for this script
SCRIPT=$(readlink -f "$0")
echo $SCRIPT
#Gets Path of script without script name
SCRIPTPATH=$(dirname "$SCRIPT")
echo $SCRIPTPATH
#Cuts everything after UPROC(.* is wildcard)/
CUTDOWN=$(sed 's/\(UPROC.*\/\).*/\1/' <<< $SCRIPTPATH)
echo $CUTDOWN
The only problem is that it output is:
/home/jim/query/UPROCL/test/bob/dircut.sh
/home/jim/query/UPROCL/test/bob
/home/jim/query/UPROCL/test/
Can some tell me what is wrong with my sed command as it is not cutting down to
/home/jim/query/UPROCL/
Because * is greedy. You want to be more selective about what characters are allowed following "UPROC" -- any non-slash
Not
sed 's/\(UPROC.*\/\).*/\1/'
but
sed -r 's,(UPROC[^/]*/).*,\1,'
Using different delimiters for the s/// command reduces the "leaning toothpick" problem.
Because the .* in the () is matching to the / at the end of test/.
You need [^/]* instead of . to not match any slashes.
When you want to know in which directory you are, why don't use pwd?
One thing which might be useful: the command pwd shows the value of the environment variable PWD (uppercase). In case you want to use the current directory as a value, you might use this.

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.)

What does an asterisk at the end of a mv command do

So I am going along and moving a bunch of files
mv /source /dest &
mv /source/* /dest/dest/ &
...
...
then I get careless and
mv /source/filena* /dest/dest/ *
OMG! ^c^c^c^c
[No Response from terminal command]
What is actually going on here?
What happens when I put an * (asterisk) at the end of a command instead of an & (ampersand)?
The shell expands the wildcard *. The mv command never sees the wildcard, only the result of the expansion.
The wildcard * expands to the list of files in the current directory in lexicographic order. If the last file is a directory, then all the preceding files (/source.filenafoo, /source/filenabar, /dest/dest, hello) are moved to that subdirectory. If the last file is not a directory, mv complains that “target a.png is not a directory” (or words to that effect).
See What does mv ./* without specifying destination do? for more detailed examples.
An asterisk at the end of a command line is treated the same way as an asterisk anywhere else on the line — it's a wildcard that matches zero or more characters. Specifically, in this instance, the * in mv /source/filena* /dest/dest/ * is replaced by the name of each & every file and folder in your current directory (except those beginning with a dot), and whatever happens to be last in this list is where mv is going to try to put everything.

linux batch rename directories and strip # character from name

i have a directory with a lot of subdirectories with a # infront of them:
#adhasdk
#ad18237
I want to rename them all and remove the # caracter
I tried to do:
rename -n `s/#//g` *
but didn't seem to work.
-bash: s/#//g: No such file or directory
Any ideas on this.
Thanks
Just use
$ rename 's/^#//' *
use -n just to check that what you think it would happen really happens.
In you example you have the clue about the wrong quotes used (backticks) in the error message
-bash: s/#//g: No such file or directory
bash is trying to execute a command named s/#//g.
No that using g (global) and not anchoring the regular expression you will replace any #, not just the one in the first position.
I don't know whether it's just a typo when you typed it here, but that "rename" command should work if:
you leave off the "-n" and
you quote the substitution with regular single-quotes and not back-quotes
The "-n" tells it to not really do anything. The back-quotes are just wrong (they mean something but not what you want here).
The problem is that you use backticks (`). You should use normal quotes:
rename -n 's/#//g' *
for DIR in \#*/
do
echo mv "$DIR" "${DIR/#\#/}"
done
I had to rename all folders inside a given folder. Each folder name had some text inside round braces. The following command removed the round braces from all folder names:
rename 's/(.+)//' *
Some distros doesn't support regexp in rename. You have to install prename. Even more, sometimes you can't install prename and you have to install gprename to have binary prename.
If you have 'prename' then just change backtick character " ` " to single quote and everything should work.
So the solution should be:
prename -n 's/#//g' *
or
prename -n 'y/#//' *

Resources