I would like to synchronize only files and folders that start with a dot in my home folder.
More specifically, I only want to synchronize the files and folders listed by:
ls -ld ~/.[^.]*
Unison command line I tried:
unison /home/username /backup/dotfiles -ui text -perms 0 -ignorenot 'Regex .[!.]*' -ignore 'Regex *[!.]'
gives the error:
Malformed pattern "Regex *[!.]".
This is a simplified example, and it would be reasonable to do this with rsync instead, but I would like to use unison because in my real use case I need bidirectional sync.
The regex syntax you're looking for is
"^.[^.]*"
Related
This command works in git 2.30.0.windows.1 through the Windows 'command' shell.
git checkout [commit hash] -- */migrations/*
It doesn't work with Mate terminal or bash (git 2.17). The problem is that they substitute the present content of the directories */migrations/* (which are empty or don't have the files that were present at the commit I want to pull them from). Mate terminal does this whether I single or double quote.
If I invoke Bash and then, at the new command line, add single or double quotes, git says that it doesn't have any files literally called */migrations/*:
error: pathspec '*/migrations/*' did not match any files known to git
I can get the content of the migrations files if I substitute directories one at a time, but there are 20+ folders of migrations and I assume I have just missed a bit of lore about how to get what I want from a Linux terminal. Can anyone suggest what I ought to be doing?
This */migrations/* syntax is referring to nowhere path. Neither root nor current working directory.
Try these with ls command before checkout with git:
*migrations/*
./*migrations/*
$PWD/migrations/*
And if you got the right output with ls then apply it to git checkout ...
Test 1
ls */tmp/*
ls: cannot access '*/tmp/*': No such file or directory
Test 2
ls /tmp/*
it has output ...
it has output ...
I often use fzf to navigate the filesystem, especially the Alt-c key binding.
When invoked, fzf generates a list from the current working directory.
Is it possible to make fzf generate a list from a specified directory?
I have tried fzf <dir>, but it results in an error (unknown option). Also, I can't find any options like -C <dir> for specifying the start directory.
I had a more general issue which might be useful for you. The following is from a blog post I wrote about it:
Configuring FZF to search useful directories beyond the working directory
I use fzf both as a command line tool and from within Vim using the fzf.vim plugin. It makes finding (and opening) files intuitive, fast, and frees you from needing to remember their location or exact name. By default, fzf searches recursively within the current directory, which is often just what you want. If you need to search for a file in some directory beyond the current working directory you need to specify that path as an argument to fzf, after which it's business as usual (fzf will recursively search the specified directory).
The Problem
It always felt a shame to have to occasionally precisely specify a path in order to get a fuzzy search going... precisely specifying a path is the exact thing that fzf is supposed to unburden your from! My initial approach was to supply the home directory path and let fzf search everything, the home directory path can be specified in only a couple of characters so there's no real burden in that case.
The problem with doing this is that you end up searching a lot of directories which you know don't have the file you want. The main offenders were directories you end up with if you install say, anaconda3. The results would be swamped with thousands of internal files, with very long paths. The long paths tended to 'soak up' any letters I entered in the search, so it was difficult for fzf to filter them out.
The Solution
You can choose which searching tool fzf uses under the hood. The default is the standard linux find command, but you can also use fd, ripgrep or silver searcher. Apart from being a lot faster than the default find, these latter tools respect .ignore files. This means that fzf will skip any files or directories listed in a .ignore file. We can turn this feature to our advantage.
First, we install fd. If you run Ubuntu 19.04 (Disco Dingo) or newer, you can install the officially maintained package:
sudo apt install fd-find
If you use an older version of Ubuntu, you can download the latest .deb package from the release page and install it via:
# adapt version number and architecture
sudo dpkg -i fd_8.2.1_amd64.deb
Now we configure fzf to use fd by adding the following line in your .bashrc:
export FZF_DEFAULT_COMMAND="fdfind . $HOME"
If you're using an older version than Ubuntu 19.10, the above line needs to be modified like so:
export FZF_DEFAULT_COMMAND="fd . $HOME"
Now fzf will always search recursively from the home directory, and respect any .ignore files. So let's make one in the home directory:
touch ~/.ignore
I find that the list of directories that I might conceivably (~15) want to recursively search with fzf is shorter that the list of directories that I would never want searched. The total number of files in the directories I want searched is about 5000 or so - easily handled by fd.
In the .ignore file, I first list all my home directories, each followed by a '/':
# start by igoring every home directory
anaconda3/
arch/
cache/
code/
Desktop/
.
.
.
Then below those, put the directories that you want to be searched, each preceded by a '!' and followed by a '/':
# now un-ignore the ones I care about
!code/
!Desktop/
!documents/
!downloads/
.
.
.
The '!' will 'cancel out' the previous ignore commands.
And there we have it. We can invoke fzf wherever we are in the file system and start typing vague things about the file(s) we have in mind and fzf will search in a set of predefined directories and find it with ease. This completely removes the barrier of thinking where a file might be and how precisely it was named.
N.B. I have noticed that, for some reason, a couple of subdirectories were not showing up in the fzf search, and so I explicitly created some '!path/to/missed/directory/' lines in this section...
N.B. You may be wondering "What if I find myself in an unusual directory not on the list, and want to use fzf?". I had the same concern so I put a couple of aliases in my .bashrc that can toggle the above configuration on and off at will (be sure to use 'fdfind' for Ubuntu 19.10+, as disused above):
# restore fzf default options ('fzf clear')
alias fzfcl="export FZF_DEFAULT_COMMAND='fd .'"
# reinstate fzf custom options ('fzf-' as in 'cd -' as in 'back to where I was')
alias fzf-="export FZF_DEFAULT_COMMAND='fd . $HOME'"
If you're using Vim to create the .ignore file, an easy way to get a list of all the directories in your home directory is the following command:
:.!ls ~/
Append a '/' to all lines by putting the cursor on the first directory in the list and entering the following command:
:.,$ norm A/
Similar to above, insert the '!' before each one by putting the cursor on the first directory in the list and entering the following command:
:.,$ norm I!
Assuming you're using bash or similar, this is built into the default completion options which get installed with fzf: https://github.com/junegunn/fzf#fuzzy-completion-for-bash-and-zsh
tldr; enter start file or directory, append ** and hit Tab. So if you'd enter cd /foo/** then tab opens fzf with /foo as start directory.
edit at the time of writing the commands for which this works are hardcoded in fzf's bash helpers, which is why this works for cat and cd but not for tac or nano. This is the complete list:
awk cat diff diff3
emacs emacsclient ex file ftp g++ gcc gvim head hg java
javac ld less more mvim nvim patch perl python ruby
sed sftp sort source tail tee uniq vi view vim wc xdg-open
basename bunzip2 bzip2 chmod chown curl cp dirname du
find git grep gunzip gzip hg jar
ln ls mv open rm rsync scp
svn tar unzip zip
To add other commands use this in e.g. your .bashrc, after the place where fzf gets sourced (something like [ -f ~/.fzf.bash ] && source ~/.fzf.bash):
__fzf_defc "tac" _fzf_path_completion "-o default -o bashdefault"
Alternatively: open an issue to ask for the commands you want to be added to fzf by default, things like tac and nano are super common anyway.
You can do something like:
find <dir> | fzf
fd . <dir> | fzf
Source.
I don't have much experience with the command line, but essentially I have a list of files in a single folder as follows:
file1_a_1
file1_a_2
file2_b_1
file2_b_2
file3_c_1
file3_c_2
And I also have a text file with the files I want. However, this list does not have the full file path, instead, it looks like this:
file1_a file3_c
because I want to move all files that start with 30 or so specific codes (i.e. everything that starts with file1_a and file1_c for all the files that start with this).
I have tried:
cp file1_a* file3_c* 'dir/dest'
but this does not work. I have also tried the find command. I think I have to use a loop to do this but I cannot find any help on looping through files with a wildcard on the end.
Thanks in advance! I am working on a linux machine in bash.
you can use the xargs command with find command and a pipe
find / -name xxxxx | xargs cp /..
As it says in the description. I first check our database is up to date
mh547:bin crashandburn4$ sudo /usr/libexec/locate.updatedb
Password: #password entered and function executed without errors
I then try and search for something inside my Documents folder
mh547:bin crashandburn4$ cd ~/Documents/
mh547:Documents crashandburn4$ ls
Mamp_workspace/ Scenarios.docx gc01/
mh547:Documents crashandburn4$ locate Scenarios.docx #nothing returned
I then try another random folder:
mh547:Documents crashandburn4$ cd ..
mh547:~ crashandburn4$ ls
Applications/ Movies/ drawable/ untitled-2.pdf
Desktop/ Music/ drawable-xhdpi/ untitled-2.synctex.gz
Documents/ Pictures/ dwhelper/ untitled-2.tex
Downloads/ Public/ linux_ssh* website-terminal-copy-paste
Dropbox/ Samsung/ scripts/ workspace/
Google Drive/ Sites/ untitled-2.aux workspace_copy_to_linux*
Library/ android-sdks/ untitled-2.log
mh547:~ crashandburn4$ locate website-terminal-copy-paste
/Users/crashandburn4/website-terminal-copy-paste #correct result returned
can anyone help me? I've been stuck on this for a good half hour or so.
As pointed out by plundra, that's because the locate OSX ships with is old and crippled and doesn't index and/or report files which are not readable by nobody, even when run as root. What you can do though is either install homebrew and then GNU locate, or, as suggested here use mdfind -name instead (I don't have an OSX box at hand to test this).
It's because your Documents-folder isn't world readable, which is a good thing, specially on shared systems.
The BUGS section of the locate(1) man-page explains it:
The locate database is typically built by user ''nobody'' and the
locate.updatedb(8) utility skips directories which are not readable
for user ''nobody'', group ''nobody'', or world. For example, if your
HOME directory is not world-readable, none of your files are in the
database.
Try running ls -ld ~/Documents and you'll see the permissions. Wikipedia have an article on Unix permissions if you are unfamiliar with these.
You can do sudo ln -s /usr/libexec/locate.updatedb /usr/local/bin/updatedb to make the updatedb command available
In editors/ides such as eclipse and textmate, there are shortcuts to quickly find a particular file in a project directory.
Is there a similar tool to do full path completion on filenames within a directory (recursively), in bash or other shell?
I have projects with alot of directories, and deep ones at that (sigh, java).
Hitting tab in the shell only cycles thru files in the immediate directory, thats not enough =/
find /root/directory/to/search -name 'filename.*'
# Directory is optional (defaults to cwd)
Standard UNIX globbing is supported. See man find for more information.
If you're using Vim, you can use:
:e **/filename.cpp
Or :tabn or any Vim command which accepts a filename.
If you're looking to do something with a list of files, you can use find combined with the bash $() construct (better than backticks since it's allowed to nest).
for example, say you're at the top level of your project directory and you want a list of all C files starting with "btree". The command:
find . -type f -name 'btree*.c'
will return a list of them. But this doesn't really help with doing something with them.
So, let's further assume you want to search all those file for the string "ERROR" or edit them all. You can execute one of:
grep ERROR $(find . -type f -name 'btree*.c')
vi $(find . -type f -name 'btree*.c')
to do this.
When I was in the UNIX world (using tcsh (sigh...)), I used to have all sorts of "find" aliases/scripts setup for searching for files. I think the default "find" syntax is a little clunky, so I used to have aliases/scripts to pipe "find . -print" into grep, which allows you to use regular expressions for searching:
# finds all .java files starting in current directory
find . -print | grep '\.java'
#finds all .java files whose name contains "Message"
find . -print | grep '.*Message.*\.java'
Of course, the above examples can be done with plain-old find, but if you have a more specific search, grep can help quite a bit. This works pretty well, unless "find . -print" has too many directories to recurse through... then it gets pretty slow. (for example, you wouldn't want to do this starting in root "/")
I use ls -R, piped to grep like this:
$ ls -R | grep -i "pattern"
where -R means recursively list all the files, and -i means case-insensitive. Finally, the patter could be something like this: "std*.h" or "^io" (anything that starts with "io" in the file name)
I use this script to quickly find files across directories in a project. I have found it works great and takes advantage of Vim's autocomplete by opening up and closing an new buffer for the search. It also smartly completes as much as possible for you so you can usually just type a character or two and open the file across any directory in your project. I started using it specifically because of a Java project and it has saved me a lot of time. You just build the cache once when you start your editing session by typing :FC (directory names). You can also just use . to get the current directory and all subdirectories. After that you just type :FF (or FS to open up a new split) and it will open up a new buffer to select the file you want. After you select the file the temp buffer closes and you are inside the requested file and can start editing. In addition, here is another link on Stack Overflow that may help.
http://content.hccfl.edu/pollock/Unix/FindCmd.htm
The linux/unix "find" command.
Yes, bash has filename completion mechanisms. I don't use them myself (too lazy to learn, and I don't find it necessary often enough to make it urgent), but the basic mechanism is to type the first few characters, and then a tab; this will extend the name as far as it can (perhaps not at all) as long as the name is unambiguous. There are a boatload of Emacs-style commands related to completion in the good ol' man page.
locate <file_pattern>
*** find will certainly work, and can target specific directories. However, this command is slower than the locate command. On a Linux OS, each morning a database is constructed that contains a list of all directory and files, and the locate command efficiently searches this database, so if you want to do a search for files that weren't created today, this would be the fastest way to accomplish such a task.