I have a script (executed with zsh 5.8; but this should not be relevant in this case) in a Cygwin environment, which takes as parameter the name of some output file and writes to this files via redirection in various places, like this:
outfile=$1
: >$outfile # Ensure that the file exists and is empty.
.... do some work
command_x >>$outfile
.... do more work
command_y >>$outfile
... and so on
I would like to modify the behviour of the script in that if no parameter is supplied, the output of the commands goes to standard output instead. I thought that it would be sufficient to modify the script in one line:
outfile=${1:-/dev/stdout}
But nothing is written to stdout. Investigating the case further, I found that instead a regular file named stdout had been created in the /dev directory. It seems that in the Cygwin environment, /dev/stdout does not represent the standard output of the process.
How would I achieve my goal under Cygwin?
UPDATE
As requested by #matzeri, here is a simple testcase:
echo x >/dev/stdout
Expected behaviour: Seeing x on stdout
Real behaviour: A regular file /dev/stdout has been created
on a standard windows installation the /dev/std* are a symlink to the /proc/self/fd/*
ls -l /dev/std*
lrwxrwxrwx 1 Marco Kein 15 Jun 19 2018 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 Marco Kein 15 Jun 19 2018 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 Marco Kein 15 Jun 19 2018 /dev/stdout -> /proc/self/fd/1
if for any reason that is not anymore true they can be recreated
by /etc/postinstall/bash.sh.done script
$ grep self /etc/postinstall/bash.sh.done
/bin/test -h /dev/stdin || ln -sf /proc/self/fd/0 /dev/stdin || result=1
/bin/test -h /dev/stdout || ln -sf /proc/self/fd/1 /dev/stdout || result=1
/bin/test -h /dev/stderr || ln -sf /proc/self/fd/2 /dev/stderr || result=1
/bin/test -h /dev/fd || ln -sf /proc/self/fd /dev/fd || result=1
In that condition the command
$ echo x > /dev/stdout
x
produces the expected output on both Bash and Zsh
I would like to have a command that closes all tmux session which name corresponds to a pattern. The pattern, in the language of regex, is nn\d+
I feel that I should be able to use a combination of grep and xargs.
I tried with
tmux ls | grep -P "nn\d+" | ..
but I am not sure how to use xargs here, that is: I am not sure how to refer to only the name part of the matched string, and to one string at the time.
To be more precise, the output of tmux ls is something like:
1: 1 windows (created Thu Mar 25 12:49:17 2021)
2: 1 windows (created Thu Mar 25 12:50:20 2021)
nn312133: 1 windows (created Thu Mar 25 12:53:54 2021)
nn3123: 1 windows (created Thu Mar 25 12:53:52 2021)
The output from grep is:
nn312133: 1 windows (created Thu Mar 25 12:53:54 2021)
nn3123: 1 windows (created Thu Mar 25 12:53:52 2021)
I should need to pipe nn312133 and nn3123 into tmux kill-session -t $x
Any idea? Thanks
Use grep -Po to make grep only print out the matched part instead of the whole line.
The answer is tmux ls | grep -Po "nn\d+" | xargs -n1 tmux kill-session -t
This problem occurs only on suse, it works on ubuntu and even on windows through babun
My point is to replace a word in several files with another word.
This is what I'm trying:
$ grep -Inrs MY_PATTERN src/ | cut -d: -f1 | xargs sed -i 's/MY_PATTERN/NEW_WORD/g'
sed: can't read path/to/a/found/file_1: No such file or directory
sed: can't read path/to/a/found/file_2: No such file or directory
sed: can't read path/to/a/found/file_3: No such file or directory
...
Knowing that
$ grep -Inrs MY_PATTERN src/ | cut -d: -f1
path/to/a/found/file_1
path/to/a/found/file_2
path/to/a/found/file_3
UPDATE1
This doesn't work either
$ grep -lZ -Irs MY_PATTERN src/ | xargs -0 ls
ls: cannot access path/to/a/found/file_1: No such file or directory
ls: cannot access path/to/a/found/file_2: No such file or directory
ls: cannot access path/to/a/found/file_3: No such file or directory
...
$ ls -al path/to/a/found/file_1 | cat -vet
-rw-r--r-- 1 webme 886 Feb 1 13:36 path/to/a/found/file_1$
UPDATE2
$ whoami
webme
$ uname -a
Linux server_vm_id_34 3.0.101-68-default #1 SMP Tue Dec 1 16:21:37 UTC 2015 (ed01a9f) x86_64 x86_64 x86_64 GNU/Linux
UPDATE3
$ grep --version
grep (GNU grep) 2.7
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Mike Haertel and others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.
$ xargs --version
xargs (GNU findutils) 4.4.0
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Eric B. Decker, James Youngman, and Kevin Dalley.
Built using GNU gnulib version e5573b1bad88bfabcda181b9e0125fb0c52b7d3b
# My project path /home/users/webme/projects/my_project
$ df -T
dl360d-01:/homeweb/users/webme nfs 492625920 461336576 31289344 94% /home/users/webme
$ id
uid=1689(webme) gid=325(web) groups=325(web)
$ mount -v
/dev/vda2 on / type btrfs (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
debugfs on /sys/kernel/debug type debugfs (rw)
udev on /dev type tmpfs (rw,mode=0755)
tmpfs on /dev/shm type tmpfs (rw,mode=1777)
devpts on /dev/pts type devpts (rw,mode=0620,gid=5)
/dev/vda1 on /boot type ext3 (rw,acl,user_xattr)
/dev/vdb on /appwebinet type xfs (rw)
rpc_pipefs on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw)
dl360d-01:/homeweb/users on /homeweb/users type nfs (rw,soft,bg,addr=xx.xx.xx.xx)
dl360d-01:/appwebinet/tools/list on /appwebinetdev/tools/list type nfs (ro,soft,sloppy,addr=xx.xxx.xx.xx)
dl360d-01:/homeweb/users/webme on /home/users/webme type nfs (rw,soft,bg,addr=xx.xxx.xx.xx)
none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
none on /var/lib/ntp/proc type proc (ro,nosuid,nodev)
I don't have exportfs, neither I have it in sudo zypper install exportfs
I'd suggest keeping it simple:
$ grep -lZ -Irs foo * | xargs -0 sed -i 's/foo/bar/g'
grep -l outputs matching file names only, which is really what you want in this pipeline. grep -Z terminates each matching file name with a NUL, which xargs -0 can pick up. This allows for file names with embedded white-space to pass between the grep and the xargs unfettered.
# show the structure
$ tree
.
└── path
└── to
└── a
└── found
├── file_1
├── file_2
└── file_3
# show the contents
$ grep . path/to/a/found/file_*
path/to/a/found/file_1:a foo bar
path/to/a/found/file_2:a foo bar
path/to/a/found/file_3:a foo bar
# try it out
$ grep -lZ -Irs foo * | xargs -0 ls -l
-rw-rw-r-- 1 bishop bishop 10 Feb 13 09:13 path/to/a/found/file_1
-rw-rw-r-- 1 bishop bishop 10 Feb 13 09:13 path/to/a/found/file_2
-rw-rw-r-- 1 bishop bishop 10 Feb 13 09:13 path/to/a/found/file_3
bishop's helpful answer is the simplest and most robust solution in this case.
This answer may still be of interest for (a) a discussion of the -d vs. the -n options, and (b) how to preview the command(s) that xargs would execute.
From what I understand, SUSE uses GNU utilities, so you can use xargs -d'\n':
grep -Inrs MY_PATTERN src/ | cut -d: -f1 | xargs -d'\n' sed -i 's/MY_PATTERN/NEW_WORD/g'
xargs -d'\n' ensures that each input line as a whole is treated as its own argument (preserving the integrity of filenames with spaces), while still passing as many arguments as possible (typically, all) at once.
(By contrast, -n 1 would break arguments by whitespace, and call the target command with 1 argument at a time.)
If you want to preview the command that would be executed, use an aux. bash command:
grep -Inrs MY_PATTERN src/ | cut -d: -f1 |
xargs -d'\n' bash -c 'printf "%q " "$#"' _ sed -i 's/MY_PATTERN/NEW_WORD/g'
Read on for an explanation.
Optional background information.
xargs has its own option, -p, for previewing the command(s) to execute and prompting for confirmation, but the preview doesn't reflect argument boundaries in the way you'd have to indicate them when calling the command directly from the shell.
A quick example:
$ echo 'hi, there' | xargs -p -d '\n' printf '%s'
printf %s hi, there ?...
What xargs will actually execute is the equivalent of printf '%s' 'hi, there', but that is not reflected in -p's prompt.
Workaround:
$ echo 'hi, there' | xargs -d '\n' bash -c 'printf "%q " "$#"' _ printf '%s'
printf %s hi\,\ there
The generic auxiliary bash command - bash -c 'printf "%q " "$#"' _, inserted just before the target command - quotes the arguments that xargs passes - on demand, only if necessary - in a way that would be required for the shell to recognize each as a single argument, and joins them with spaces.
The net result is that a shell command is printed that is the equivalent of what xargs would execute (though, as you can see, there is no guarantee that the input quoting style is retained).
I need to run sed -e 'command' -e 'command' file.txt but I get this error on mac: sed: -e: No such file or directory. Any idea how to fix this?
Works fine with my sed:
$ echo ax | sed -e 's/a/b/' -e 's/x/y/'
by
$ uname -a
Darwin Equinox.local 12.3.0 Darwin Kernel Version 12.3.0: Sun Jan 6 22:37:10 PST 2013; root:xnu-2050.22.13~1/RELEASE_X86_64 x86_64
$ which sed
/usr/bin/sed
So the problem must be elsewhere. Judging by your command given in comments, I would try passing the '' argument to the -i option:
$ sed -i '' -e "s/\.$REGIONID\./\./" -e "/\.$NONREGIONID\./d" application.conf
With the caveat described in the man page:
If a zero-length extension is given, no backup will be saved. It is
not recommended to give a zero-length extension when in-place editing
files, as you risk corruption or partial content in situations where
disk space is exhausted, etc.
Basically my question is how to use bash shell command to do following automatically, so I can track modified files easily.
list svn check-out files
create link files to above files in an directory called "change"
laptop$ svn status -q
M rcms/src/config/ta_show.c
M rcms/src/config/ta_config.c
laptop$ cd change
laptop$ link -s ../rcms/src/config/ta_show.c ta_show.c
laptop$ link -s ../rcms/src/config/ta_config.c ta_config.c
laptop$ ls
lrwxrwxrwx 1 root root 59 Nov 27 12:24 ta_show.c -> ../rcms/src/config/ta_show.c
lrwxrwxrwx 1 root root 59 Nov 27 12:24 ta_config.c -> ../rcms/src/config/ta_config.c
I am thinking to use shell command like below:
$ svn status -q | sed 's/M //' | xargs -I xxx ln -s ***BETWEEN REAL FILE AND BASE FILENAME***
you have two things need to be concerned:
the empty line between each file with svn status 'M'
extract the file name
the awk one liner could do it:
awk '$0{x=$2;gsub(".*/","",x);print "ln -s ../"$2" "x}'
so if you pipe your svn status output to the line above, it print the ln -s command lines for you.
if you want the ln -s lines to get executed, you could either pipe the output to sh (svn status|awk ...|sh) or replace the print with system
at the end i would like to show the output below as an exmple:
kent$ echo "M rcms/src/config/ta_show.c
M rcms/src/config/ta_config.c"|awk '$0{x=$2;gsub(".*/","",x);print "ln -s .."$2" "x}'
ln -s ../rcms/src/config/ta_show.c ta_show.c
ln -s ../rcms/src/config/ta_config.c ta_config.c