New answers tagged shell
0
This script works for me on macOS
#!/usr/bin/env bash
set -u # exit on undefined variable
bash -c 'set -o pipefail' # return code of first cmd to fail in a pipeline
# Print random open port. Inspired by
# https://superuser.com/a/1041677/537059
CHECK="do while"
while [[ ! -z $CHECK ]]; do
PORT=$(((RANDOM % 60000) + 1025))
# ...
3
According to the manual 3.6.4 Redirecting Standard Output and Standard Error:
3.6.4 Redirecting Standard Output and Standard Error
This construct allows both the standard output (file descriptor 1) and
the standard error output (file descriptor 2) to be redirected to the
file whose name is the expansion of word.
There are two formats for redirecting ...
0
The process running the script exits, because it reaches the end of the script.
It reaches the end of the script, because the command is run in the background with &.
0
When you start a process in the background (using &), it starts executing concurrently with its parent. Since your script does not have anything else to do, it exits and the orphaned process is adopted by init. When you do not use &, the parent waits for the child to finish, suspending itself. and you see the script as parent. In the latter case, ...
3
If your variables have the same number of lines then you could use the pr command to print standard output into two columns ex.
$ printf '%s\n' "$varA" "$varB" | pr -2 -Ts^I
Aug 01 04:25
Aug 16 03:39
Aug 26 10:06
where ^I stands for the TAB character (to be consistent with the default separator of the paste command) and may be ...
4
Here is my proposal if I understood correctly:
for i in *.nc; do
[[ "$i" =~ _([0-9]{8})[_.] ]] && d="${BASH_REMATCH[1]}"
mkdir -p "${d:0:4}/${d:4:2}"
mv "$i" "${d:0:4}/${d:4:2}"
done
4
Looping through years and months:
#!/bin/bash
for year in {2001..2020} ; do
mkdir $year
for month in {01..12} ; do
mkdir $year/$month
mv gpm_cressman_${year}${month}* $year/$month
done
done
In case you have too many files with long names per year & month (you claim "thousands"), bash might reach its limits ("argument list ...
4
Assuming the date is always in the same position in the filename, put this in a script:
#!/bin/bash
#
while $# -gt 0 ; do
file="$1"
shift
year="$( echo "$file" | cut -c 14-17)"
mnth="$( echo "$file" | cut -c 18-19)"
[[ -d $year/$mnth ]] || mkdir -p $year/$mnth
echo mv "$file" ...
0
Not sure if this is of any use to anyone... This is the quick and nasty solution I came up with to sync files between two remote systems that the host is authorized to access, but where the remotes cannot access each other:
(){ local RSYNC_TMP=$(mktemp); rsync -aP src-host:~/filename $RSYNC_TMP; rsync -aP $RSYNC_TMP dest-host:~/filename; rm -rf $RSYNC_TMP }
...
1
As people have already told you in the comments, this is a very bad idea. You will never be sure you've cleaned everything up and standard procedure for something like this is to wipe the sever and restore from a clean backup.
That said, the reason your find command isn't working is because find doesn't understand extended globbing patterns like !("....
1
Instead of
exepath=which exe
(this command just runs exe, previously setting the environment variable exepath to literal value which)
you should use
exepath=`which exe`
or
exepath=$(which exe)
0
You can unload the completion system completely like this:
zmodload -u zsh/compctl zsh/complete
bindkey '^I' forward-word
Instead of inserting completions, Tab will now accept the next word from zsh-autosuggestions.
Before you give up completely on completions, though, may I suggest you give the zsh-autocomplete plugin a try? It gives you Visual Studio ...
0
In order to cancel all my slurm jobs (omitting the OP's grep 197), I found I had to prune the fist line of the squeue output, which contained column titles, also:
squeue -u $USER | awk '{print $1}' | tail -n+2 | xargs scancel
-1
ls | tr '\n' '\n' >filename.txt
This can save file names of the directory in the file.
0
How about this, sorry but I do not have many platforms to try it on
local __shell=`ps $$ -o comm=""`
0
Put the lines
MATLAB_HOME="/usr/local/MATLAB/R2018a/bin"
PATH="$MATLAB_HOME:$PATH"
into ~/.profile or ~/.bashrc
3
Many shells keep a record of commands which they have found on the PATH, so that they don’t need to explore all the PATH entries when a known command is invoked. You can see this e.g. on Bash or Zsh by running the
hash
command.
Some shells such as Tcsh might only consider this record of commands: by default Tcsh scans the path when it starts, and when the ...
-1
Besides the link mentioned by @pLumo with various options I would suggest to consider to use pretty old but useful&powerful find. I use it a lot.
With options like:
-anewer File was last accessed more recently than file was modified.
-cnewer File's status was last changed more recently than file was modified.
-atime ...
-ctime ...
-mtime ...
-amin/...
0
Indeed rmlint seems better suited for the task than rdfind. I like that it outputs a shell script, which you can examine to verify that it doesn't propose to do something you didn't really intend.
For your use case, I was drawn to the section of the manual that talks about Flagging original directories, since you clearly have an "original" ...
1
scp -o User='foo@bar@baz#quux' host:/rpath lpath
scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \
-o User='DB6164@DB6164CP#example.net@y96553.example.net#22' \
PsmpDblanVip.example.net:/tmp/file.txt file.txt
0
Simply use the flag -L:
From the man page:
-L, --dereference
dereference all symbolic links
Then du calculates the size no matter whether they are symbolic or not.
1
Side-stepping the questions you've raised with a pragmatic solution, you can set up a default mapping for this target, which will simplify it for all ssh transport uses.
I'm splitting DB6164@DB6164CP#example.net@y96553.example.net#22@PsmpDblanVip.example.net into user DB6164@DB6164CP#example.net@y96553.example.net#22 and CyberArk proxy PsmpDblanVip.example....
1
set -o extendedglob
first_set=("$@[1,(i)^-*]")
first=${(j[ ])first_set}
would store in $first the concatenation of all arguments up to the first that doesn't start with - with one space character in between.
Then for $second, you can get the rest:
second_set=("$@[$#first_set + 1, -1]")
second=${(j[ ])second_set}
In any case, note that ...
answered Jan 13 at 7:12
Stéphane Chazelas
405k7171 gold badges795795 silver badges12081208 bronze badges
2
In the first case, ls list the contents the /dev/fd -> /proc/self/fd -> /proc/<pid_of_ls>/fd, and in the second case, that of /proc/<pid_of_the_shell>/fd.
While /dev/fd is a (magical) symbolic link to /proc/self/fd, . (the current directory, as listed by ls when called without arguments) isn't, and it was already resolved to /proc/<...
3
You can try this:
shopt -s globstar
for f in **/*.lri; do
[[ ! $(find . -name "$(basename "${f%%.lri}").dng") ]] && realpath "$f"
done
answered Jan 12 at 22:12
schrodigerscatcuriosity
5,16911 gold badge1010 silver badges3333 bronze badges
1
tl;dr:
find . -name "*.txt" | perl -nle 's/\.txt$/.foo/; print unless -e' | cat -v
Here's an example using Perl
Note that we have a c.foo missing
$ ls
a.foo a.txt b.foo b.txt c.txt
We can find it this way
$ ls *.txt | perl -nle 's/\.txt$/.foo/; print unless -e '
c.foo
c.foo is missing
Update: dealing with filenames that contain ...
0
I had an issue where I could not login (on Ubuntu 20.04). I added the following tweak to huangzonghao's answer:
# autoload tmux - place at EOF (end-of-file) within ~/.bashrc
# if shell is interactive, and TMUX var is set...
[[ $- == *i* ]] && [[ -z "${TMUX}" ]] && { tmux attach || exec tmux new-session && exit; }
1
you have files on jchab1:/scripts that match /scripts/*
so
ssh jchadb2 ls -l /scripts/*.sh
first, expand localy to
ssh jchadb2 ls -l /scripts/habak_trans.sh .. (no _v2 files)
next, ls -l /scripts/habak_trans.sh .. is sent to jchab2 (and still no _v2. file)
and on remote hosts, only explicit file are listed.
compare
ssh jchadb2 ls -l /scripts/*.sh
and
ssh ...
1
assuming you don't have any "newlines" in filenames, this should work:
cd B
find . -type f -print | while read f
do
[[ -f "A/$f" ]] || { echo mv "$f" "A/$f" ; continue; }
cmp "$f" "A/$f" && echo rm "$f"
done
Run it, and if it looks good, remove the "echo" words ...
1
answer to your explicit question
Yes, there is a way to script console interaction: Expect. Quite a few resources out there (https://core.tcl-lang.org/expect/index seems to be a good starting point); Exploring Expect by Libes (ISBN 9781565920903) is a fine book on the subject.
A special case: if there is only one thing to enter from keyboard (say “foo”), ...
1
Using a shell expansion with a leading zero does what you need.
#/bin/bash
newdir="testing_$RANDOM"
mkdir "${newdir}"; cd "${newdir}"
for y in {2000..2022}; do
for m in {01..12}; do
touch "prefix_$y$m.txt"
done
done
0
You can use date for generating dates in shell with custom format
$ date +%Y-%m-%d -d "2002-03-28 +1 days"
2002-03-29
$ date +%Y-%m-%d -d "2002-03-28 +1 months"
2002-04-28
$ date +%Y-%m-%d -d "2002-03-28 +1 years"
2003-03-28
1
I would start by challenging your requirements. You are trying to do everything in one step. You'd be much better off knowing what you want the restored system to look like before you start restoring files.
It's actually easier to get the diff first than you might think.
Step 1
Get the hash of every file on disk. You're going to have to do this anyway. ...
2
Here's a method that's simple, but inefficient if a lot of files are missing in A. Just do each step in turn. I assume that there are only directories and regular files (comparing metadata for special files is doable with a bit more work). Warning: untested code.
First, copy files that are present in B but not in A to A. Preserve metadata (timestamps, ...
answered Jan 11 at 21:27
Gilles 'SO- stop being evil'
669k162162 gold badges13951395 silver badges18981898 bronze badges
3
Step 2 and 3 seem the most difficult, so let's start with those.
There is a tool called rdfind which finds duplicate files. You can decide what to do when a duplicate is detected: in your case you would want to delete it from B: rdfind -deleteduplicates true A B. If identical files exist in A and in B, the one from A is preserved. Other options are to ...
1
I want to do a binary search on all the extensions that I have loaded to isolate the problem one.
Here's a solution that approaches this problem from a divide and conquer perspective. The basic idea is to prepare the input file a tiny bit, then recursively divide it in halves; each half is output as a sample command and then recurses on those halves. You ...
0
Do any of the common Linux utilities allow changing to arbitrary UID given CAP_SETUID?
No, they don't.
I know I could compile a small setuid(2) application, but it's cumbersome to transfer it into e.g. containers everytime I want to test user namespace functionality.
If you plan to do your testing framework in bash, everything will be "cumbersome&...
1
It's not really clear exactly what you're trying to achieve. From your question you might be:
Attempting to execute something as a different user for testing without the overhead of creating that user every time
Attempting to run a process as a user that doesn't exist (with not matching entry in /etc/passwd or more precisely with getent passwd)
Attempting ...
10
You need to enable extended globs for +([0-9]) to work. It's probably set in your bashrc, so is enabled in the interactive shell, but not in the script. Add shopt -s extglob to the script to enable it. See Pattern Matching in the manual.
Without it, the pattern doesn't match, and ${var/pattern/replacement} leaves the value as-is.
0
You can use bash, instead of playing with Java.
#!/bin/bash
admins_mail=youraddress@example.com
quota_exceeded=80
df -h | grep -vE 'hostname_or_IP_address:/mount/point|tmpfs|cdrom|Used' | awk '{ print $5 " " $1 }' | while read output; do
status=$(echo $output | awk '{ print $1}' | cut -d'%' -f1 )
echo $status
partition=$(echo $output | awk '{ ...
10
Stéphane Chazelas has an excellent answer on pointing out differences in syntax between narrowly POSIX-compliant shells and other shells, and other pitfalls. This answer will take a different approach.
As a human it can be difficult to take a script written for bash, ksh, or some other shell with their non-POSIX extensions and safely translate the entire ...
16
I don't agree conditions are easier to make with ((...)) and [[...]] (assuming that's what you're referring to; note that those operators are not specific to bash and come from ksh) than the standard [ or test command. [[ ... ]] and (( ... )) have several problems of their own¹ and which are much worse than those of [.
If your [ fails with an unexpected ...
answered Jan 10 at 8:11
Stéphane Chazelas
405k7171 gold badges795795 silver badges12081208 bronze badges
-2
I'd say the most important thing to avoid is [[ ... ]]. Arithmetic in between (( ... )) probably doesn't work either.
Make it a habit to put variables in quotes to avoid errors when a variable is not set, such as "$var".
All operators, arithmetic or logical, are words with dashes such as -eq or -a instead of = or &&.
Also use shellcheck.net ...
1
You can combine a couple of commands:
$ cat /proc/$(xprop | grep PID | awk '{print $3}')/cmdline | tr '\0' ' ';echo
xprop will wait until you click on a window. When you do, it prints the process id number and other info (grep and awk clean that up) and cat shows the file /proc/cmd/PID/cmdline which holds the command line, with arguments, but uses zero as ...
-2
You can do this very simply with the built-in bash operator -ef:
[[ file1 -ef file2 ]] && echo Same
If the condition evaluates to true (file1 and file2 are the same), then it prints "Same". Otherwise, nothing is output.
0
2020 answer
Append
# Calc
c(){
echo "scale=2; $*" | bc -l
}
to your ~/.aliases, then
$ c 1/3
.33
(The original issue has been solved multiple times already. However, the title "Simple command-line calculator" may require division to some decimal points. The use of the -l option with bc seems to give 20 decimal points, which is ...
4
If your shell is zsh (which AFAIK is the default in newer versions of macos), you can set the autopushd option (set -o autopushd in your ~/.zshrc) which will cause zsh to remember all the places (current working directories, changed with cd/pushd/popd) you've been.
Then, you can see that stack with:
dirs
Or dirs -v, so see the index of each directory on the ...
answered Jan 9 at 10:26
Stéphane Chazelas
405k7171 gold badges795795 silver badges12081208 bronze badges
1
How about this function?
hg_fold() {
local -a config
mapfile -t config < <(hg debugconfig)
local -a opts
for i in "$@"; do
opts+=( --config "${config[i-1]}" )
done
opts+=(
--exact
-r 2024:8679fc70eae8
-r 2021:8b3257871eac
-m "Fold"
)
echo ...
2
A simple brute force approach that'll work in any awk in any shell on all Unix boxes:
$ cat tst.awk
s=index($0,"START") { $0=substr($0,s); f=1 }
f { rec = rec $0 RS }
END {
len = length(rec)
for (i=1; i<=len; i++) {
char = substr(rec,i,1)
if ( char == "{" ) {
++cnt
}
else if ( char == ...
1
With pcregrep:
start_word='START'
pcregrep -Mo "(?s)\Q$start_word\E\h*(\{(?:[^{}]++|(?1))*+\})" < your-file
With zsh builtins:
set -o rematchpcre
start_word='START'
[[ $(<your-file) =~ "(?s)\Q$start_word\E\h*(\{(?:[^{}]++|(?1))*+\})" ]] &&
print -r -- $MATCH
Those use PCRE's recursive regexp feature, where (?1) above ...
answered Jan 8 at 17:25
Stéphane Chazelas
405k7171 gold badges795795 silver badges12081208 bronze badges
Top 50 recent answers are included
Related Tags
shell × 10350bash × 3502
shell-script × 2042
linux × 1146
scripting × 629
command-line × 603
quoting × 482
awk × 405
zsh × 385
terminal × 364
sed × 345
io-redirection × 345
text-processing × 341
files × 337
ssh × 328
find × 328
grep × 308
wildcards × 295
pipe × 289
environment-variables × 230
variable × 210
ubuntu × 177
process × 166
filenames × 162
directory × 158