Tag Info

New answers tagged

1

Bash has no feature to expand just one match out of many. The pattern @(foo) matches just one occurrence of the pattern foo. That is, it matches foo, but not foofoo. This syntactic form is useful to build or patterns like @(foo|bar), which matches either foo or bar. It can be used as part of longer patterns like @(foo|bar)-*.txt, which matches ...


3

"one match" doesn't mean what you think it does. It means one match within the pattern, not to only return one file. ls doesn't have any options like that. Normally, people do things like ls |head -1 or similar.


2

With simple -name: find /var/log -name '*.[2-9]' or for any digit: find /var/log -name '*.[[:digit:]]' or if other chars are possible after digit: find /var/log -name '*.[2-9]*'


1

To find the filenames which ends with a number ranges from . [1 to 5]. find /var/log/ -type f -regextype sed -regex ".*\.[1-5]$"


1

If it is ok to have the full path of the files in the tar archive you can do: tar -c -f ar.tar $(readlink -e a b c d) The -e option to readlink will canonicalize existing filenames and silently ignore any others.


0

you can try tar cf ar.tar $(ls a b c d ) where c for create f ar.tar sepcify tar file $(ls a b c d) will list to stdin which file are realy present (and give error for other)


0

One additional difference between the two is that shell globs (like /home/user/*) don't usually include "hidden files" (filenames that begin with a dot). On the other hand, find will match all filenames except the special directories '.' and '..' (current and parent directory).


0

Another approach of explaining it: When * is used then the shell knows what the single elements are. The find output is just a long string. The shell does not know what the elements (and their separators) are. Command substitution can be used in a special way with a program that produces quoted output; then the problem would not appear. But in order to make ...


4

This is standard practice for shells. The order of operations is command substitution ($(find .)), then word splitting, then glob expansion (/home/user/*). From the POSIX standard (word splitting = field splitting; glob expansion = pathname expansion): The order of word expansion shall be as follows: Tilde expansion (see Tilde Expansion), ...


4

The shell does things in order. $(find .) is called command substitution. The results of command substitution are subjected: word splitting, pathname expansion quote removal Word splitting is what causes the problem when there are file names with spaces. /home/user/* is pathname expansion. Note that that is second to last on the above list. It is ...


0

Another safe approach that should work on any GNU system and Busybox: tail -n5 "$(stat -c "%Y %n" ./* | sort -nk1,1 | cut -d ' ' -f 2- | tail -n1)" That will work on most things but if your file names can contain newlines, use this instead (GNU only, still breaks if your files end in newlines): tail -n5 "$(stat --printf "%Y %n\0" ./* | sort ...


7

With the zsh shell: tail -n 5 ./*.aff(D.om[1]) With other shells, it's quite difficult to come up with something reliable if you don't want to make assumptions on what file names may contain. For instance, the bash equivalent, if you're on a recent GNU system would be: find . -maxdepth 1 -name '*.aff' -type f -printf '%T@:%p\0' | sort -rzn | sed -zn ...


5

Assuming file names don't contain newline characters and that all the *.aff files are regular files: ls -t1d -- *.aff | head -n 1 gives you the name of the most recently modified .aff-file. If you want the last 5 lines just do: tail -n 5 -- "$(ls -t1d -- *.aff | head -n 1)"


0

With GNU du (i.e. on non-embedded Linux or Cygwin), you can use the --exclude option to exclude the files you don't want to match. du -s --exclude='*.html' /var/foo If you want to positively match *.pdf files, you'll need to use some other method to list the files, and du will at least display one output line per argument, plus a grand total with the ...


1

You can let the shell expand the files: $ mkdir foo $ echo "abc" > foo/1.pdf $ echo "abcd" > foo/2.pdf $ echo "abcd" > foo/3.html $ du -ch foo/*.pdf 4,0K foo/1.pdf 4,0K foo/2.pdf 8,0K total However as you can see this indiates filesizes about 1000 times as just created. A better option is using the -b option: $ du -cbh foo/*.pdf 4 ...


1

Simply list both patterns if you want to match files that match either pattern, that is, files that match *.txt and files that match *.csv, or in other words, files that match *.txt or *.csv. (The nesting of quantifiers and logical operators matters!) rm *.txt *.csv Note that if either pattern does not match any file, it will be left intact, so rm will ...


2

Use the logrotate command. That's the command that handles your log files in /var/log. It can rotate logs based on date or size. Look at /etc/cron.daily/logrotate and /etc/logrotate.conf. You should just be able to put an entry in /etc/logrotate.conf to handle the file your want to rotate. Also see this website: ...


2

On a GNU system, with that particular file name pattern, ls -r | uniq -w23 would give you the ones to keep. So you could move them away: ls -r | uniq -w23 | xargs mv -t ../to-keep/ And remove all the remaining files. 23 is the length of vtm_data_12month_201409. So uniq would return only the first file (in the reversely sorted list of files) among the ...


0

Checking validity of date and generating date range is difficult and error prone using bash script. The best choice would be to use python or perl or any other higher level scripting languages which can do indepth checks. I have updated the script so that it can delete files within a range of date and excluding the range of date. The options will be like ...


0

Do you need to solve this problem generally or just once? If you just need to solve it once, sometimes a simple solution is best. We can use brace expansion in Bash: rm vtm_data_12month_2014{09,10}{01..29}.txt This might work in your case since: The number of arguments that we will send to rm is unlikely to send us over ARG_MAX, and The day you want ...


-1

in zsh: [[ $string = $~pattern ]] && print true


2

Simply: rm *.txt *.csv And if your shell supports brace expansion, you can: rm *.{txt,csv}


0

I would use grep thusly: #!/bin/bash string="/foo/bar" pattern1="/foo/*" pattern2="/foo/{bar,baz}" if echo $string | grep -e "$pattern1" > /dev/null; then echo $string matches $pattern1 fi if echo $string | grep -e "$pattern2" > /dev/null; then echo $string matches $pattern2 fi Which gives the output: ./test2.bsh /foo/bar matches /foo/* ...


1

I don't believe that {bar,baz} is a shell glob pattern (though certainly /foo/ba[rz] is) but if you want to know if $string matches $pattern you can do: case "$string" in ($pattern) put your successful execution statement here;; (*) this is where your failure case should be ;; esac You can do as many as you like: case "$string" in ($pattern1) ...


2

There is no general solution for this problem. The reason is that, in bash, brace expansion (i.e., {pattern1,pattern2,...} and filename expansion (a.k.a. glob patterns) are considered separate things and expanded under different conditions and at different times. Here is the full list of expansions that bash performs: brace expansion tilde expansion ...


0

As Patrick pointed out you need a "different type" of pattern: [[ /foo/bar == /foo/@(bar|baz) ]] string="/foo/bar" pattern="/foo/@(bar|baz)" [[ $string == $pattern ]] Quotes are not necessary there.


1

The multi-line answers above didn't suit my desire for a one-line solution and not modifying the environment. Here is a generic one-liner that may work for you: echo $(ls FOO* 2>/dev/null | wc -w) the /dev/null is because ls throws an error if there's no file. This just ignores ls and counts the number of files found based on the number of "words" ...


2

Thanks to goldilocks for help, using -maxdepth solved my issues. The problem was that I was giving -maxdepth after -path. The following syntax works as expected: find . -maxdepth 1 -path \*/pages/*/index.css


0

Make some fake test files: (only for this example) $ touch filename_{1000000000..1000000099..5}.gz Grab a "time" range of files from ls output and pass this to echo: $ echo $(ls | awk -F'[_,]' '1000000044<=$2 && $2<=1000000066') filename_1000000045.gz filename_1000000050.gz filename_1000000055.gz filename_1000000060.gz ...


0

Not as simple, but my 'weapon of choice' python my_mrjob.py $( for f in {1413324000..1413410400}; do [ -f filename_$f.gz ] && echo $f; done ) PS: IMHO, the python job itself should be modified to allow for range entry, with additional intelligence to skip over non existent files. Will be much faster and simpler. The {a..b} syntax is not a lazy ...


11

shopt -s extglob echo rm foo.!(org) This is "foo." followed by anything NOT "org" ref: https://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching



Top 50 recent answers are included