How to use variable as a path for find command - string

Can someone give me a hint, how I can make the following bash script run properly:
path="/path/"
excludepath="! -path \"/path/to/exclude/*\" "
find "$path" "$excludepath" -name *."txt" -type f
When I try to run it I get:
find: `! -path "/path/to/exclude/*"': No such file or directory
Thank you in advance.

Your problem was the fact that "$excludepath" is a single argument, even if it contains spaces. To put several arguments, use an array of strings instead of a string:
excludepath=(! -path "*webshow*")
find "$path" "${excludepath[#]}" -name "*.txt" -type f
This is a bashism, though (people that stumble onto this and don't use bash will need to do something else).

Related

Unix brace expansion within find command

This is working fine:
$ echo email_{ldn,nyk,asp}.log
Similarly, I wanted to find filenames which differ slightly:
$ find ~ -type f -name email_{ldn,nyk,asp}.log
But above command results in error:
find: paths must precede expression: email_nyk.log
Any help on brace expansions within find command will be very much appreciated.
The error message results from the expansion of the pattern by your shell.
Assuming you have the files email_ldn.log, email_nyk.log and email_asp.log in your current directory, your command
find ~ -type f -name email_{ldn,nyk,asp}.log
will be expanded to
find ~ -type f -name email_ldn.log email_nyk.log email_asp.log
which results in the error message.
To prevent the expansion of a pattern by the shell you have to quote the pattern. Unfortunately, find doesn't support patterns with a list of alternatives in braces, so using this pattern with find will not work as you might expect.
find ~ -type f -name "email_{ldn,nyk,asp}.log" # Does not work as intended.
find ~ -type f -name "email_*.log" # This would work, but matches other files as well.
If you have GNU find, you could use a regular expression instead.
find ~ -type f -regextype posix-extended -regex ".*/email_(ldn|nyk|asp).log"
Brace expansion is not the way to do this sort of thing, and eval is evil, but you could do:
eval find ~ -type f -and \\\( -false "-or -name "email_{ldn,nyk,asp}.log \\\)
The main idea is that -name email_ldn.log email_nyk.log email_asp.log does not work, because you want the expression to be -name email_ldn.log -or -name email_nyk.log -or -name email_asp.log, so you create that expression with the brace expansion. But then find receives -or -name email_???.log as a single argument instead of 3 arguments, so you need to force word splitting with eval. Overall, a nasty, ugly solution.
If you want to find all files with one prefix you can use this command:
find ~ -type f -name "email_*.log"
In this situation you don't need to use braces. Don't forget to put " (quotes) before and after the pattern of the name.
find doesn't support braces to set alternatives, like the shell does. So, if you want to find specific files, you can do this in 2 steps: first find all files with 'email' prefix and then grep for specific files. Try this:
find ~ -type f -name "email*" | egrep "email_(ldn|asp|nyk).log"
It was realized eventually during the conquest, some of you have suggested using eval, but I think it would better to use xargs :
As the aim is to find files matching the brace expansion and execute few command thereafter, so xargs suites this purpose nicely.
$ ls ~/email_{ldn,nyk,asp}.log | xargs -I %% sh -c 'chomd 644 %% && cp -arf %% ~/feed_dir'

Replace a file if path of the file contains a string in Linux [duplicate]

I know how to find files using
find . -name "file_name"
But if I am given one part of a path, say "folder1/subfolder2/", how do I get all the full path that contains this partial path?
Example
partial path: folder1/subfolder2/
desire result:
/bob/folder1/subfolder2/yo/
/sandy/folder1/subfolder2/hi/
Use the -path option:
find . -path '*/folder1/subfolder2/*'
You may do it like below:
find . -path "*folder1/folder2" -prune -exec find {} -type f -name file.txt \;
With -prune you don't recurse after first match in a directory
This one worked for me (using bash)
ls -l /**/folder1/subfolder2/**
I came up with this, other solutions did not work for me,
find1 is a function
find1 ()
{
for file in `find -name $1`;
do
full_path=$PWD/$file;
echo $full_path;
done
}
If you dont want to stay posix-compliant, at least on Linux you can also use the -regex (and -regextype) option for this purpose.
For instance:
find folder/ -regextype posix-extended -regex "(.*/)?deer/(.*/)?beer"
will match
folder/deer/beer
folder/deer/dir/forest/beer/
folder/forest/deer/dir/forest/beer/
etc.
See linux man for details.

Linux bash command -backup=numbered. Put the number BEFORE the file extension

Using a one-line bash command with GitBash on windows, using find and cp, I am backing up a bunch of script files that exist in multiple sub-directories. I am currently backing them up to a single directory. As you can imagine, naming conflicts arise. This is easy enough to avoid with the --backup=numbered option which creates a copy of the file. However, the problem with this is that it puts the number AFTER the file extension, naming the file like this: example.js.~2~. What I want is to preserve the file extension and name the file like this: example2.js rather than putting the number after the file extension. Is there any way to do this?
Another option would be to prepend the directory name (from the directory that it is being copied from) to the file that is being copied instead of adding a number. I would accept either of these as a solution.
Here is what I have so far:
find . -path "*node_modules*" -prune -o -type f \( -name '*.js' -or -name '*.js.map' -or -name '*.ts' -or -name '*.json' \) -printf "%h\n" -exec cp {} --backup=numbered "/c/test/" \;
Any help would be appreciated! Thank you!
what about :
#!/bin/bash
# your find command here
FILES=$(find . -type f .....)
# loop through files and create a new filename with the path within ( slashes replaced by underscores
for FILE in $FILES; do
NEW_FILENAME=$(printf "%s" "$FILE" | sed s/\\//_/g)
cp "$FILE" "/c/test/${NEW_FILENAME}"
done
from your question, I am unsure if a one liner is mandatory...

Why does find . -name foo* fail?

OK, probably a stupid question, but why doesn't this work?
find . -name Orna* -ls
It seems that "find" should be able to handle this simple request... Am I missing something here? This should be a basic execution of the "find" command, but linux is being stupid, or maybe I am.
correct way of using Find Command are the following phrases
find . -type f -name "filename" # this command used to find files from the curent dir
find . -type d -name "dir name" # this command used to find dirs from the curent dir
find /. -type f -name "filename" # this command used to find files from the system
find /. -type d -name "dir name" # this command used to find dirs from the system
I wish it be a helpful for you
You need to quote the name parameter so the shell doesn't expand the wildcard, e.g.
find . -name "Orna*" -ls
To explain the "why" a little more than existing answers do -- wildcards are expanded by the shell before the command being invoked is run. Thus, let's say your current directory contains files Orna1 and Orna2.
In that case, when you run
find . -name Orna* -ls
...what's actually invoked by the shell is:
find . -name Orna1 Orna2 -ls
...thus, find never sees the wildcard expression at all!
Quoting the expansion, as in:
find . -name 'Orna*' -ls
...prevents the shell from trying to expand the wildcard before running your command, thus preventing this issue.

A question about command "find"

find . \( -name "_*" -or -newer while2 \) -type f -print
In the linux command above , why _* should be quoted ?
First, the shell expands all unquoted *'s to match file names in the local directory.
After that, the shell runs the find command with that list of file names.
Generally, you don't want the shell to do '*' globbing in the local directory. Generally, you wind the find command to do filename matching in other directories.
The shell has several other things it does before running a command. $VARIABLE replacement is one of those.
Why _* should be quoted ?
If it isn't, your shell might expand the * to be substituted with files in the current directory. That's probably not what you wanted here.
if you don't quote it, the shell (bash?) would try to expand. if there's any file that starts with '_' on the current directory, you'd get something like:
find . \(-name _somefile _someother _file3 .... -or -newer while2 \) -type f -print
certainly not what you want. i always quote patterns, just to be sure the shell won't mess with them

Resources