I was trying to remove a file within a repository which contained a "$" symbol, so I used:
rm *$*
But this deleted all my files in the directory and attempted to delete all subdirectories as well.
Can someone explain why this command did not just remove files containing a $?
*$* first undergoes parameter expansion, with $* expanding to a string consisting of all the current positional parameters. If there are none, the result is *, which then undergoes pathname expansion.
The correct command would have been something like rm *"$"* or rm *\$*, with the $ escaped to prevent any parameter expansion from taking place before pathname expansion.
Related
I have the following input.
Entities can be 'MG SOCRATES' 'VALIND' 'SUSBTECT'
This entities have the following directories.
/home/tca/git/tca/<entity>
Example :
/home/tca/git/tca/MG SOCRATES
/home/tca/git/tca/VALIND
/home/tca/git/tca/SUSBTECT
In each directory I have files with this pattern something_or-something.
For example:
/home/tca/git/tca/SUSBTECT/asdsad2018-01-01-2018-12-31sdadsda
/home/tca/git/tca/SUSBTECT/asdsad2018-01-01_2018-12-31sdsadadsda
I want to move them to a subdicretory for each entity with the following structure.
I have for example this subdirectory.
/home/tca/git/tca/SUSBTECT/2018-01-01_2018-12-31
What I want to do is to move from /home/tca/git/tca/SUSBTECT/ all files that matches the pattern _or- to the subdirectory.
My code does it correctly but fails for entity 'MG SOCRATES' because there is a space that moves command can not interpretate.
My code:
entity_path="$entity_path""/*"$file_start"*"$file_end"*"
echo `mv -t "$path" $entity_path`
Where $entity_path all files matching the pattern and $path is the directory where I want to move my files.
I think is a problem about the spaces.
Any idea?
There is no way to have a regular parameter expansion that undergoes pathname expansion, but not word-splitting, so your attempt to put the pattern in entity_path is going to fail. Either use the pattern directly,
mv -t "$path" "$entity_path"/*"$file_start"*"$file_end"*
or store the result of the pathname expansion in an array.
entities=( "$entity_path"/*"$file_start"*"$file_end"* )
mv -t "$path" "${entities[#]}"
I have two files in my directory:
com.my.arsys.core.js
com.my.arsys.core-libs.js
Now I want to match these using globbing pattern (curly braces) and copy them to a folder so I run the following:
cp com.my.arsys.{core, core-libs}.js a
However I get the following errors:
cp: cannot stat 'core,': No such file or directory
cp: cannot stat 'core-libs,': No such file or directory
I think the problem is with the syntax. Can anyone please help?
You have an extra blank, try:
cp com.my.arsys.{core,core-libs}.js a
From bash man about Brace Expansion:
A correctly-formed brace expansion must contain unquoted opening and closing braces, and at least one unquoted comma or a valid sequence expression. Any incorrectly formed brace expansion is left unchanged.
I am trying to list all files located in specific sub-directories of a directory in my bash script. Here is what I tried.
root_dir="/home/shaf/data/"
sub_dirs_prefixes=('ab' 'bp' 'cd' 'cn' 'll' 'mr' 'mb' 'nb' 'nh' 'nw' 'oh' 'st' 'wh')
ls "$root_dir"{$(IFS=,; echo "${sub_dirs_prefixes[*]}")}"rrc/"
Please note that I do not want to expand value stored in $root_dir as it may contain spaces but I do want to expand sub-path contained in {} which is a comma delimited string of contents of $sub_dirs_prefixes. I stored sub-directories prefixes in an array variable, $sub_dirs_prefixes , because I have to use them later on for something else.
I am getting following error:
ls: cannot access /home/shaf/data/{ab,bp,cd,cn,ll,mr,mb,nb,nh,nw,oh,st,wh}rrc/
If I copy the path in error message and run ls from command line, it does display contents of listed sub-directories.
You can command substitution to generate an extended pattern.
shopt -s extglob
ls "$root_dir"/$(IFS="|"; echo "#(${sub_dirs_prefixes[*]})rrc")
By the time parameter can command substitutions have completed, the shell sees this just before performing pathname expansion:
ls "/home/shaf/data/"/#(ab|bp|cd|cn|ll|mr|mb|nb|nh|nw|oh|st|wh)rrc
The #(...) pattern matches one of the enclosed prefixes.
It gets a little trickier if the components of the directory names contain characters that need to be quoted, since we aren't quoting the command substitution.
I am trying to remove files in a directory using rm and without deleting the directory itself in a script. The examples I see only do this while in the directory itself, and I would like to do it without navigating there.
I tried
rm "$(dirname $1)/filetokeep/*"
but it is not working. Any help?
Quoting the wildcard inhibits expansion.
rm -- "$(dirname -- "$1")/filetokeep"/*
Using -- ensures that values can't be interpreted as optional arguments rather than positional ones (so that things still work if the directory named in $1 starts with a -).
I have a simple test bash script which looks like that:
#!/bin/bash
cmd="rsync -rv --exclude '*~' ./dir ./new"
$cmd # execute command
When I run the script it will copy also the files ending with a ~ even though I meant to exclude them. When I run the very same rsync command directly from the command line, it works! Does someone know why and how to make bash script work?
Btw, I know that I can also work with --exclude-from but I want to know how this works anyway.
Try eval:
#!/bin/bash
cmd="rsync -rv --exclude '*~' ./dir ./new"
eval $cmd # execute command
The problem isn't that you're running it in a script, it's that you put the command in a variable and then run the expanded variable. And since variable expansion happens after quote removal has already been done, the single quotes around your exclude pattern never get removed... and so rsync winds up excluding files with names starting with ' and ending with ~'. To fix this, just remove the quotes around the pattern (the whole thing is already in double-quotes, so they aren't needed):
#!/bin/bash
cmd="rsync -rv --exclude *~ ./dir ./new"
$cmd # execute command
...speaking of which, why are you putting the command in a variable before running it? In general, this is a good way make code more confusing than it needs to be, and trigger parsing oddities (some even weirder than this). So how about:
#!/bin/bash
rsync -rv --exclude '*~' ./dir ./new
You can use a simple --eclude '~' as (accoding to the man page):
if the pattern starts with a / then it is anchored to a particular spot in
the hierarchy of files, otherwise it
is matched against the end of the
pathname. This is similar to a leading
^ in regular expressions. Thus "/foo"
would match a name of "foo" at either
the "root of the transfer" (for a
global rule) or in the merge-file's
directory (for a per-directory rule).
An unqualified "foo" would match a
name of "foo" anywhere in the tree
because the algorithm is applied
recursively from the top down; it
behaves as if each path component gets
a turn at being the end of the
filename. Even the unanchored
"sub/foo" would match at any point in
the hierarchy where a "foo" was found
within a directory named "sub". See
the section on ANCHORING
INCLUDE/EXCLUDE PATTERNS for a full
discussion of how to specify a pattern
that matches at the root of the
transfer.
if the pattern ends with a / then it will only match a directory, not a
regular file, symlink, or device.
rsync chooses between doing a simple string match and wildcard
matching by checking if the pattern
contains one of these three wildcard
characters: '*', '?', and '[' .
a '*' matches any path component, but it stops at slashes.
use '**' to match anything, including slashes.