Is it possible to redirect output of a file to ls.
Example: file has a / in it and I want to direct that to ls to get the content of the / directory. When I try ls < file this does not work
You can use xargs or command substitution to achieve this.
Use xargs
The key is knowledge of the xargs command.
If you have a list of files in a file called files_to_change, you
can print them with the following one liner:
cat files_to_change | xargs ls
Use command substitution
An alternate method is to use command substitution. This works
the same as above.
Two different one-liners, using different syntax:
ls `cat files_to_change`
ls $(cat files_to_change)
It won't matter if they are files or directories, and you can run any command on them.
If the contents of file_to_change was:
/usr/bin/
/bin/
cat files_to_change | xargs ls and ls $(cat files_to_change) would be equivalent to running:
$ ls /usr/bin/
$ ls /bin/
The output on the console should be what you want.
You need to use xargs. This very useful utility runs a command with arguments which are passed in as input:
cat myfile | xargs ls
ls 'cat your_file'
beware, the ' is the altGr+7 char (but used for formatting here !)
Related
I am trying to write a shell script that reads a file line by line and executes a command with its arguments taken from the space-delimited fields of each line.
To be more precise, I need to download a file from an URL which is given in the second column to the path given in the first column using wget. But I don't know how to load this file and get the values in script.
File.txt
file-18.log https://example.com/temp/file-1.log
file-19.log https://example.com/temp/file-2.log
file-20.log https://example.com/temp/file-3.log
file-21.log https://example.com/temp/file-4.log
file-22.log https://example.com/temp/file-5.log
file-23.pdf https://example.com/temp/file-6.pdf
Desired output is
wget url[1] -o url[0]
wget https://example.com/temp/file-1.log -o file-18.log
wget https://example.com/temp/file-2.log -o file-19.log
...
...
wget https://example.com/temp/file-6.pdf -o file-23.pdf
Use read and a while loop in bash to iterate over the file line-by-line and call wget on each iteration:
while read -r NAME URL; do wget "$URL" -o "$NAME"; done < File.txt
Turning a file into arguments to a command is a job for xargs:
xargs -a File.txt -L1 wget -o
xargs -a File.txt: Extract arguments from the File.txt file.
-L1: Pass all arguments from 1 line to the command.
wget -o Pass arguments to the wget command.
You can count, using a for loop and the output of seq like so:
In bash, you can add numbers using $((C+3)).
This will get you:
COUNT=6
OFFSET=18
for C in `seq "$((COUNT-1))"`; do
wget https://example.com/temp/file-${C}.log -o file-$((C+OFFSET-1)).log
done
wget https://example.com/temp/file-${COUNT}.pdf -o file-$((COUNT+OFFSET-1)).pdf
Edit: Sorry, I misread your question. So if you have a file with the file mappings, you can use awk to get the URL and the FILE and then do the download:
cat File.txt | while read L; do
URL="$(echo "${L}" | awk '{print $1}'"
FILE="$(echo "${L}" | awk '{print $2}'"
wget "${URL}" -o "${FILE}"
done
I need a shell script to remove files without an extension (like .txt or any other extension). For example, I found a file named as imeino1 (without .txt or any other thing) and I want to delete them via shell script, so if any developer know about this part, please explain how to do it.
No finds, no pipes, just plain old shell:
#!/bin/sh
for file in "$#"; do
case $file in
(*.*) ;; # do nothing
(*) rm -- "$file";;
esac
done
Run with a list of files as argument.
Assuming you mean a UNIX(-like) shell, you can use the rm command:
rm imeino1
rm -rvf `ls -lrth|grep -v ".txt"`
ls -lrth|grep -v ".txt" should be inside back-quotes `…`(or, better, inside $(…)).
If other filenames are not containing "." then instead of giving .txt for grep -v, you can give
rm -rvf `ls -lrth|grep -v "."`
This will remove all the directories and files in the path without extension.
rm -vf `ls -lrth|grep -v "."` won't remove directories, but will remove all the files without extension (if the filename does not contain the character ".").
for file in $(find . -type f | grep -v '\....$') ; do rm $file 2>/dev/null; done
Removes all files not ending in .??? in the current directory.
To remove all files in or below the current directory that contain no dot in the name, regardless of whether the names contain blanks or newlines or any other awkward characters, you can use a POSIX 2008-compliant version of find (such as found with GNU find, or BSD find):
find . -type f '!' -name '*.*' -exec rm {} +
This looks for files (not directories, block devices, …) with a name that does not match *.* (so does not contain a .) and executes the rm command on conveniently large groups of such file names.
I've searched high and low to try and work out how to batch process pandoc.
How do I convert a folder and nested folders containing html files to markdown?
I'm using os x 10.6.8
You can apply any command across the files in a directory tree using find:
find . -name \*.md -type f -exec pandoc -o {}.txt {} \;
would run pandoc on all files with a .md suffix, creating a file with a .md.txt suffix. (You will need a wrapper script if you want to get a .txt suffix without the .md, or do ugly things with subshell invocations.) {} in any word from -exec to the terminating \; will be replaced by the filename.
I made a bash script that would not work recursively, perhaps you could adapt it to your needs:
#!/bin/bash
newFileSuffix=md # we will make all files into .md
for file in $(ls ~/Sites/filesToMd );
do
filename=${file%.html} # remove suffix
newname=$filename.$newFileSuffix # make the new filename
# echo "$newname" # uncomment this line to test for your directory, before you break things
pandoc ~/Sites/filesToMd/$file -o $newname # perform pandoc operation on the file,
# --output to newname
done
# pandoc Catharsis.html -o test
This builds upon the answer by geekosaur to avoid the .old.new extension and use just .new instead. Note that it runs silently, displaying no progress.
find -type f -name '*.docx' -exec bash -c 'pandoc -f docx -t gfm "$1" -o "${1%.docx}".md' - '{}' \;
After the conversion, when you're ready to delete the original format:
find -type f -name '*.docx' -delete
without having to write a shell script, I'm wondering if there's a way to list files based on a match to more than one criteria?
I know I can do:
ls ./files/ | grep samp
to get a list of all files that contain "samp" in the filename... But, is there a way to say, "list all of the files that match "samp" or "examp"?
I already figured out that
ls ./files/ | grep samp examp
doesn't work...
Use find - it's much more powerful for doing this kind of thing, e.g.:
find ./files -name \*samp\* -o -name \*examp\*
You can use |:
ls ./files/ | grep -E 'samp|examp'
The -E is to allow the use of extended (modern) regular expressions. If your version of grep doesn't support that behaviour, you'll need to escape the |:
ls ./file/ | grep 'samp\|examp'
ls ./files/ | grep -esamp -eexamp
You can use the find command.
find ./files -name \*samp\* -o -name \*examp\*
The -o means "or". You can use -iname instead of -name for case-insensitive matching.
How do I find out the files in the current directory which do not contain the word foo (using grep)?
If your grep has the -L (or --files-without-match) option:
$ grep -L "foo" *
You can do it with grep alone (without find).
grep -riL "foo" .
This is the explanation of the parameters used on grep
-L, --files-without-match
each file processed.
-R, -r, --recursive
Recursively search subdirectories listed.
-i, --ignore-case
Perform case insensitive matching.
If you use l (lowercased) you will get the opposite (files with matches)
-l, --files-with-matches
Only the names of files containing selected lines are written
Take a look at ack. It does the .svn exclusion for you automatically, gives you Perl regular expressions, and is a simple download of a single Perl program.
The equivalent of what you're looking for should be, in ack:
ack -L foo
The following command gives me all the files that do not contain the pattern foo:
find . -not -ipath '.*svn*' -exec grep -H -E -o -c "foo" {} \; | grep 0
The following command excludes the need for the find to filter out the svn folders by using a second grep.
grep -rL "foo" ./* | grep -v "\.svn"
If you are using git, this searches all of the tracked files:
git grep -L "foo"
and you can search in a subset of tracked files if you have ** subdirectory globbing turned on (shopt -s globstar in .bashrc, see this):
git grep -L "foo" -- **/*.cpp
You will actually need:
find . -not -ipath '.*svn*' -exec grep -H -E -o -c "foo" {} \; | grep :0\$
I had good luck with
grep -H -E -o -c "foo" */*/*.ext | grep ext:0
My attempts with grep -v just gave me all the lines without "foo".
Problem
I need to refactor a large project which uses .phtml files to write out HTML using inline PHP code. I want to use Mustache templates instead. I want to find any .phtml giles which do not contain the string new Mustache as these still need to be rewritten.
Solution
find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'
Explanation
Before the pipes:
Find
find . Find files recursively, starting in this directory
-iname '*.phtml' Filename must contain .phtml (the i makes it case-insensitive)
-exec 'grep -H -E -o -c 'new Mustache' {}' Run the grep command on each of the matched paths
Grep
-H Always print filename headers with output lines.
-E Interpret pattern as an extended regular expression (i.e. force grep
to behave as egrep).
-o Prints only the matching part of the lines.
-c Only a count of selected lines is written to standard output.
This will give me a list of all file paths ending in .phtml, with a count of the number of times the string new Mustache occurs in each of them.
$> find . -iname '*.phtml$' -exec 'grep -H -E -o -c 'new Mustache' {}'\;
./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
./app/MyApp/Customer/View/Account/studio.phtml:0
./app/MyApp/Customer/View/Account/orders.phtml:1
./app/MyApp/Customer/View/Account/banking.phtml:1
./app/MyApp/Customer/View/Account/applycomplete.phtml:1
./app/MyApp/Customer/View/Account/catalogue.phtml:1
./app/MyApp/Customer/View/Account/classadd.phtml:0
./app/MyApp/Customer/View/Account/orders-trade.phtml:0
The first pipe grep :0$ filters this list to only include lines ending in :0:
$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$
./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
./app/MyApp/Customer/View/Account/studio.phtml:0
./app/MyApp/Customer/View/Account/classadd.phtml:0
./app/MyApp/Customer/View/Account/orders-trade.phtml:0
The second pipe sed 's/..$//' strips off the final two characters of each line, leaving just the file paths.
$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'
./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml
./app/MyApp/Customer/View/Account/studio.phtml
./app/MyApp/Customer/View/Account/classadd.phtml
./app/MyApp/Customer/View/Account/orders-trade.phtml
When you use find, you have two basic options: filter results out after find has completed searching or use some built in option that will prevent find from considering those files and dirs matching some given pattern.
If you use the former approach on a high number of files and dirs. You will be using a lot of CPU and RAM just to pass the result on to a second process which will in turn filter out results by using a lot of resources as well.
If you use the -not keyword which is a find argument, you will be preventing any path matching the string on the -name or -regex argument behind from being considered, which will be much more efficient.
find . -not -regex ".*/foo/.*" -regex ".*"
Then, any path that is not filtered out by -not will be captured by the subsequent -regex arguments.
For completeness the ripgrep version:
rg --files-without-match "pattern"
You can combine with file type and search path, e.g.
rg --files-without-match -t ruby "frozen_string_literal: true" app/
another alternative when grep doesn't have the -L option (IBM AIX for example), with nothing but grep and the shell :
for file in * ; do grep -q 'my_pattern' $file || echo $file ; done
My grep does not have any -L option. I do find workaround to achieve this.
The ideas are :
to dump all the file name containing the deserved string to a txt1.txt.
dump all the file name in the directory to a txt2.txt.
make the difference between the 2 dump file with diff command.
grep 'foo' *.log | cut -c1-14 | uniq > txt1.txt
grep * *.log | cut -c1-14 | uniq > txt2.txt
diff txt1.txt txt2.txt | grep ">"
find *20161109* -mtime -2|grep -vwE "(TRIGGER)"
You can specify the filter under "find" and the exclusion string under "grep -vwE". Use mtime under find if you need to filter on modified time too.
Open bug report
As commented by #tukan, there is an open bug report for Ag regarding the -L/--files-without-matches flag:
ggreer/the_silver_searcher: #238 - --files-without-matches does not work properly
As there is little progress to the bug report, the -L option mentioned below should not be relied on, not as long as the bug has not been resolved. Use different approaches presented in this thread instead. Citing a comment for the bug report [emphasis mine]:
Any updates on this? -L completely ignores matches on the first line of the file. Seems like if this isn't going to be fixed soon, the flag should be removed entirely, as it effectively does not work as advertised at all.
The Silver Searcher - Ag (intended function - see bug report)
As a powerful alternative to grep, you could use the The Silver Searcher - Ag:
A code searching tool similar to ack, with a focus on speed.
Looking at man ag, we find the -L or --files-without-matches option:
...
OPTIONS
...
-L --files-without-matches
Only print the names of files that don´t contain matches.
I.e., to recursively search for files that do not match foo, from current directory:
ag -L foo
To only search current directory for files that do not match foo, simply specify --depth=0 for the recursion:
ag -L foo --depth 0
This may help others. I have mix of files Go and with test files. But I only need .go files. So I used
ls *.go | grep -v "_test.go"
-v, --invert-match select non-matching lines see https://stackoverflow.com/a/3548465
Also one can use this with vscode to open all the files from terminal
code $(ls *.go | grep -v "_test.go")
grep -irnw "filepath" -ve "pattern"
or
grep -ve "pattern" < file
above command will give us the result as -v finds the inverse of the pattern being searched
The following command could help you to filter the lines which include the substring "foo".
cat file | grep -v "foo"