Tag Info

Hot answers tagged

12

You don't need any external utility, you can do it with the shell's own string manipulation functionality. This makes it easier to avoid breaking on file names with special characters. And remember to always use double quotes around variable substitutions. mv -v -- "$i" "${i%.*.*}.${i##*.}" (Obviously this snippet assumes that the file name does contain ...


4

Highly recommend You should read this wonderful answer for more details. Setting IFS contains digit can break your code: $ IFS=0 $ echo test $ [ $? -eq 0 ] && echo done bash: [: : integer expression expected Some shells may inherit IFS from environment (dash, ash), some don't (bash, zsh, ksh). But someone can control the environment, your ...


4

Easy rename with mmv command: $ mmv -n '*.*.*' '#1.#3' or with rename command: $ rename -n 's:(.*)\..*(\..*):$1$2:' *


4

If you need to validate a filename match - and so only rename those files which actually have the two extensions you're attempting to modify - you can just do: case ${i##*/} in (*.*.*) mv -- "$i" "${i%.*.*}.${i##*.}" ;;esac Understand that if you do not validate the match and you're setting "$i" with a glob like: for i in * mv "$i" ... ...then using ...


4

Using a bash regex: f=foo.bar.baz.qux if [[ $f =~ (.+)\.[^.]+\.([^.]+)$ ]];then new="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" if [[ -f "$new" ]]; then echo "moving $f would overwrite $new" else echo mv "$f" "$new" fi fi mv foo.bar.baz.qux foo.bar.qux This has the advantage of doing nothing if there are less than 2 dots in ...


4

> /usr/bin/time -v sleep 1 Command being timed: "sleep 1" User time (seconds): 0.00 System time (seconds): 0.00 Percent of CPU this job got: 0% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.01 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set ...


4

Not only does ksh use sfio but it uses its own custom memory allocator. Nevertheless, my guess is sfio makes the difference in this case. I just tried to run your example under strace and can see that ksh calls read/write ~200 times (65 KB blocks) while sed does it ~3400 times (4 KB blocks). With sed -u my laptop almost melted, reads are done per byte and ...


4

Read Why does my shell script choke on whitespace or other special characters? to understand the why. The 1-sentence version is: always use double quotes around variable substitutions. echo "$firstcontent" >/tmp/myfirstcontentfiles.txt mostly works: it doesn't collapse whitespace or expand wildcards in the value of the variable. However this still ...


4

an awk command: awk -v OFS=: ' FNR==1 { # the last non-blank line from the previous file if (line) {print filename, fnr, line} filename=FILENAME line="" p=0 } /^[[:blank:]]*$/ {next} !p { # the first non-blank line print FILENAME, FNR, $0; p=1 } {fnr=FNR; line=$0} END ...


4

So I like sed the answer can be for file in file.log.* do echo "file: $file" echo -n "first line: " cat "$file" | sed -n '/^\s*$/!{p;q}' echo -n "last line: " tac "$file" | sed -n '/^\s*$/!{p;q}' done


4

List all shell variables bash : use set -o posix ; set. The POSIX options is there to avoid outputing too much information, like function definitions. zsh : use typeset Shell variables and environment variables An environment variable is available to forked child processes (as a copy. if parent process change the variable, the childs are not aware of ...


3

Try: awk -F'\n' -vRS="" ' { print "file: " FILENAME; gsub(/\n[[:blank:]]+|[[:blank:]]+\n/,""); print "first line: " $1; print "last line: " $NF; } ' file.log.*


3

Csh, bash, ksh, zsh, have a suspend builtin command (or alias, in ksh) that does exactly that. This command is mostly equivalent to sending a TSTP signal to the shell; bash and zsh do a bit of additional signal handler and juggling, and in these shells the suspend command works even if the shell is currently ignoring TSTP. You can also send the signal to ...


3

To evaluate an arithmetic expression, the shell first expands variable and command substitutions inside it. For example, in echo "$(($num1+$num2))", the first thing that happens is that $num1 and $num2 are replaced by the variables' values. The expression becomes 2+5. This is parsed as an arithmetic expression and evaluated to the number 7. The result of ...


2

You could do it using bash/ksh : for i in *.svg; do test -e "${i%.*}.png" && rm "$i"; done Or, formatted differently : for i in *.svg; do test -e "${i%.*}.png" && rm "$i" done Replace the rm with echo to test before doing the actual deleting. EDIT : sputnick just edited a solution very similar to this in his answer, you should ...


2

Try doing this using perl : (remove the i modifier in the substitution if you want to be case sensitive) $ perl -e ' foreach my $file (<*.png>) { ($ext_free = $file) =~ s/\.png//i; unlink "$ext_free.svg" if -e "$ext_free.svg"; } ' *.[Pp][Nn][Gg] To try it before, put a print instead of unlink. or using bash : shopt -s ...


2

Most likely jobs is a built-in command in your shell. If you are using bash then run man bash and search for jobs at the beginning of the line (press / to start searching and then ^ *jobs). You should see the following: jobs [-lnprs] [ jobspec ... ] jobs -x command [ args ... ] The first form lists the active jobs. The options have the following ...


2

Technically, you don't need to quote the left-hand side within [[ ... ]]. But as St├ęphane Chazelas put it in comments on his beautiful answer, there's no compelling reason not to quote it, so just do it and sleep better at night. It's a good recommended practice, less doubts and questions asked. In old-style [ ... ] you must quote, you don't have a choice. ...


2

Another approach would be to use head and tail: EDIT (Thank you for the suggestion @don_crissti!) for file in file.log.* do echo "file: $file" echo -n "first line: " grep -v '^\s*$' "$file" | head -n1 echo -n "last line: " grep -v '^\s*$' "$file" | tail -n1 done


2

The problem turned out to be that the decimal point separator in my Ubuntu installation was set to , (comma) instead of . (dot). I changed it with the following command: sudo update-locale LC_NUMERIC="en_GB.UTF-8" And the problem was resolved.


2

The thing is that if pkg-* does not match any file in current directory it's passed to dpkg as it is. It's actually bad idea. One should quote it all the time. For example: dpkg -l pkg-\*


2

if you type something like ls -l|grep foo your shell will start two processes (ls and grep). It will (because of the pipe |) also connect them to one pipeline. An interactive shell will also provide job control. This means you can do things like pausing a job or putting it in background. Typing sleep 10& will run a process, the shell will also assign it ...


2

You can use this perl script : #!/usr/bin/perl # Base on http://search.cpan.org/~pkent/Schedule-Cron-Events-1.8/cron_event_predict.plx # initial release 20091001 use warnings; use strict; use Schedule::Cron::Events; use Getopt::Std; use Time::Local; use vars qw($opt_f $opt_h $opt_p); getopts('p:f:h'); if ($opt_h) { usage(); } my $filename = shift || ...


2

In your example apt-get update didn't exit with error, because it considered the problems as warnings, not as fatally bad. If there's a really fatal error, then it would exit with non-zero status. One way to recognize anomalies is by checking for these patterns in stderr: Lines starting with W: are warnings Lines starting with E: are errors You could ...


2

You can change your cron string to: * * * * * /bin/sh commannd1..; /bin/tcsh command2... ; /bin/zsh command3 This is the more extreme case. But you can prefix the name of the specific shell before the commands. Another option is echo all the commands to the specific shell * * * * * echo 'comand1...;command2....;command3...' | /bin/sh


2

If you are already root and you run sudo $SHELL it will just run a new instance of the shell on top of the old one and not prompt for a password. You can verify this by typing exit or pressing CtrlD to exit the child shell, again it will appear as if nothing happens. Try echo $SHELL instead.


1

There are several ways to pass this information from the calling script to the called script. One is to use a parameter (./script --init vs. ./script) or a parameter value (./script --init=0 vs. ./script --init=1). I guess the most simple method is to use an environment variable: script B: init=0 while whatever; do INIT=$((init++)) ./script_A; done ...


1

What? No Perl? for file in file.log.*; do echo "FILE: $file"; perl -ne 'if(/\S/){$k++; $l=$_}; print "First line: $_" if $k==1; END{print "Last line: $l\n"}' "$file"; done Explanation for file in file.log.* : iterate over all files whose names starts with file.log. in the current directory and save each of them ...


1

For completion, here is a sed answer that only reads through each file once (hopefully faster than multiple sed, cat and tac invocations, if the files are large): for file in file.log.*; do echo "file: $file" sed -n " /[^[:space:]]/ { # Match first non-whitespace line h # Copy to hold buffer s/^/first ...


1

Pure bash example You can yank a substring from a bash variable using variable manipulation ${::} like so x="9999991385"; echo ${x:0:4}; # prints 9999 Although what your doing in or getting from 'one file' isn't exactly clear to me, you can compare strings like so: x="9999991385"; [[ "${x:0:4}" == "some string" ]] && some_thing_useful_here;



Only top voted, non community-wiki answers of a minimum length are eligible